|
| 1 | +--- |
| 2 | +title: Integrating Github OAuth with Web3Auth for Authentication |
| 3 | +image: "guides/banners/github.png" |
| 4 | +description: Learn how to integrate Github OAuth with Web3auth |
| 5 | +type: guide |
| 6 | +tags: [github, oauth, authentication] |
| 7 | +date: March 8, 2024 |
| 8 | +author: Web3Auth Team |
| 9 | +order: 1 |
| 10 | +communityPortalTopicId: |
| 11 | +--- |
| 12 | + |
| 13 | +import SEO from "@site/src/components/SEO"; |
| 14 | + |
| 15 | +<SEO |
| 16 | + title="Integrating Github OAuth with Web3Auth for Authentication" |
| 17 | + description="Learn how to integrate Github OAuth with Web3auth." |
| 18 | + image="https://web3auth.io/docs/guides/banners/github.png" |
| 19 | + slug="/guides/github-oauth" |
| 20 | +/> |
| 21 | + |
| 22 | +This guide will cover the basics of how to integrate Web3Auth with GitHub OAuth for authentication. Web3Auth is employed to provide Ethereum private |
| 23 | +key access and public address and GitHub OAuth is used to authenticate users |
| 24 | + |
| 25 | +Full example: https://github.com/Web3Auth/web3auth-pnp-examples/tree/main/web3auth-byoa/github-oauth-connection |
| 26 | + |
| 27 | +We use two web3auth libraries in this project: `@web3auth/ethereum-provider` and `@web3auth/node-sdk`. |
| 28 | + |
| 29 | +To install them, run: `npm install @web3auth/ethereum-provider @web3auth/node-sdk` |
| 30 | + |
| 31 | +## How it works? |
| 32 | + |
| 33 | +As explain in the [github OAuth Docs](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps#web-application-flow), The |
| 34 | +web integration would be like this steps: |
| 35 | + |
| 36 | + |
| 37 | + |
| 38 | +1. Request a user's GitHub identity |
| 39 | + |
| 40 | + - `GET https://github.com/login/oauth/authorize` |
| 41 | + |
| 42 | +2. Users are redirected back to your site by GitHub |
| 43 | + |
| 44 | + - Exchange this code for an access token: |
| 45 | + - `POST https://github.com/login/oauth/access_token` |
| 46 | + - ``` |
| 47 | + Accept: application/json |
| 48 | + { |
| 49 | + "access_token":"gho_16C7e42....e178B4a", |
| 50 | + "scope":"repo,gist", |
| 51 | + "token_type":"bearer" |
| 52 | + } |
| 53 | + ``` |
| 54 | + |
| 55 | +3. The Token is sent to Web3auth (Instead of access the Github API.) |
| 56 | + - Github sends a `id_token` to the app. This JWT token is sent to the Web3Auth SDK's login function. Web3Auth SDK will generate a private key for |
| 57 | + the user, in a self custodial way, resulting in easy onboarding for your user to the application. |
| 58 | + |
| 59 | +## Create a JWKS file |
| 60 | + |
| 61 | +A JWKS stands for JSON Web Key Set. It is a set of keys containing the public keys that should be used to verify any JSON Web Token (JWT) issued by |
| 62 | +the authorization server and signed using the RS256 signing algorithm. |
| 63 | + |
| 64 | +If you don't know how to create a JWKS, you can follow this |
| 65 | +[web3auth tutorial](https://web3auth.io/docs/auth-provider-setup/byo-jwt-providers#how-to-create-jwks). This file must be located on a public |
| 66 | +endpoint. To test the example, you will need to modify the file located in the root directory of the project. |
| 67 | + |
| 68 | +Both the private and the public keys, that you used to create the JWKS, must be in the server directory. In our project, they are called `private.pem` |
| 69 | +and `public.pem`. |
| 70 | + |
| 71 | +## Set up Custom JWT Verifier |
| 72 | + |
| 73 | + |
| 74 | + |
| 75 | +To create a custom verifier for your JWT Provider, you'll need the follow this steps: |
| 76 | + |
| 77 | +1. The verifier Identifier, which would be the name. This name should be used in your .ENV file as `WEB3AUTH_VERIFIER`. |
| 78 | + |
| 79 | +2. **JWT Verifier ID**: JWT Verifier ID is the unique identifier to publicly represent a user on a verifier. e.g: `sub`, `email`, or even a custom |
| 80 | + field of your JWT payload that is unique in your system for each user. In this case, we are using the `sub` field. |
| 81 | + |
| 82 | +3. **JWK Endpoint**: An endpoint containing the JWKS used to sign the JWT. In my example I'm using a static github url file. |
| 83 | + |
| 84 | +4. In the Select JWT Validation. You will add `iss` and `aud` fields (eplace both with your real Github Client ID.). |
| 85 | + - The `iss` field is the issuer of the JWT. In this case "https://github.com" |
| 86 | + - The `aud` field is the audience of the JWT. In this case "https://github.com/login/oauth/access_token" |
| 87 | + |
| 88 | + |
| 89 | + |
| 90 | +## How to create a App in Github |
| 91 | + |
| 92 | +- In the upper-right corner of any page on GitHub, click your profile photo. |
| 93 | +- Navigate to your account settings. |
| 94 | +- For an app owned by a personal account, click Settings. |
| 95 | +- For an app owned by an organization: (Click Your organizations.) |
| 96 | +- To the right of the organization, click Settings. |
| 97 | +- In the left sidebar, click Developer settings. |
| 98 | +- In the left sidebar, click GitHub Apps or OAuth apps. |
| 99 | + |
| 100 | + |
| 101 | + |
| 102 | +You have to configure you Homepage URL: `http://localhost:5005` and the callback URL `http://localhost:5005/github/callback` |
| 103 | + |
| 104 | +After creating the app, you'll need the Client Application ID into the .ENV file. Then click on "Generate a new client secret" and copy to use it also |
| 105 | +in the .ENV file. |
| 106 | + |
| 107 | +## Running the example |
| 108 | + |
| 109 | +Execute `npm run dev`. To initiate the Github OAuth flow, Open your browser to `http://localhost:5005/github/login` |
| 110 | + |
| 111 | +Finally, after loginning in as a result, you will receive in the callback url a JSON with the user data, the JWT token, the Ethereum address and |
| 112 | +private key. |
| 113 | + |
| 114 | +```json |
| 115 | +{ |
| 116 | + "userData":{ |
| 117 | + "login":"<alias>", |
| 118 | + "id":<id>, |
| 119 | + "node_id":"MSSSSS", |
| 120 | + "gravatar_id":"", |
| 121 | + "url":"https://api.github.com/users/<name>", |
| 122 | + "type":"User", |
| 123 | + "site_admin":false, |
| 124 | + "name":"Name", |
| 125 | + "company":"Web3Auth", |
| 126 | + "location":"AR, CABA", |
| 127 | + "email":null, |
| 128 | + "hireable":null, |
| 129 | + "bio":"<description>", |
| 130 | + "twitter_username":null, |
| 131 | + "public_repos":43, |
| 132 | + "public_gists":0, |
| 133 | + "followers":10, |
| 134 | + "following":12, |
| 135 | + "created_at":"2011-07-28T17:24:29Z", |
| 136 | + "updated_at":"2024-02-29T15:54:30Z" |
| 137 | + }, |
| 138 | + "jwtToken":"eyJhbGciOiJSUzI1NiIsInR5cC....oWw", |
| 139 | + "ethData":{ |
| 140 | + "ethPrivateKey":"f8fe70c14868b709b0....1498a9db5", |
| 141 | + "ethPublicAddress":[ |
| 142 | + "0x3d9c0cfff5c0a25....5a53fd6f4b678990f9" |
| 143 | + ] |
| 144 | + } |
| 145 | +} |
| 146 | +``` |
| 147 | + |
| 148 | +## Code guide |
| 149 | + |
| 150 | +In the example, we are using express for the server. This are the Endpoint that we are using: |
| 151 | + |
| 152 | +- The initial endpoint to start the Github OAuth flow. |
| 153 | + |
| 154 | +```javascript |
| 155 | +app.get("/github/login", (req, res) => { |
| 156 | + res.redirect(`https://github.com/login/oauth/authorize?client_id=${githubClientId}&redirect_uri=${githubRedirectUri}`); |
| 157 | +}); |
| 158 | +``` |
| 159 | + |
| 160 | +- The Callback endpoint to receive the JWT token and exchange it for an access token. |
| 161 | + |
| 162 | +```javascript |
| 163 | +app.get("/github/callback", async (req, res) => { |
| 164 | + const code = req.query.code; |
| 165 | + try { |
| 166 | + const accessToken = await exchangeCodeForAccessToken(code); |
| 167 | + const userData = await fetchGitHubUserDetails(accessToken); |
| 168 | + const jwtToken = generateJwtToken(userData); |
| 169 | + const ethData = await getPrivateKey(jwtToken, userData.id.toString()); |
| 170 | + res.json({ userData, jwtToken, ethData }); |
| 171 | + } catch (error) { |
| 172 | + console.error(error); |
| 173 | + res.status(500).send("Error during GitHub authentication"); |
| 174 | + } |
| 175 | +}); |
| 176 | +``` |
| 177 | + |
| 178 | +In the `getPrivateKey` function, we use Web3auth to establish a connection with the provider and get both the address and the private key. |
| 179 | + |
| 180 | +```javascript |
| 181 | +const getPrivateKey = async (idToken: string, verifierId: string) => { |
| 182 | + const web3authNodeprovider = await web3auth.connect({ |
| 183 | + verifier: process.env.WEB3AUTH_VERIFIER, |
| 184 | + verifierId, |
| 185 | + idToken, |
| 186 | + }); |
| 187 | + // The private key returned here is the CoreKit Key |
| 188 | + const ethPrivateKey = await web3authNodeprovider.request({ method: "eth_private_key" }); |
| 189 | + const ethPublicAddress = await web3authNodeprovider.request({ method: "eth_accounts" }); |
| 190 | + const ethData = { |
| 191 | + ethPrivateKey, |
| 192 | + ethPublicAddress, |
| 193 | + }; |
| 194 | + return ethData; |
| 195 | +}; |
| 196 | +``` |
| 197 | + |
| 198 | +References |
| 199 | + |
| 200 | +- [Custom JWT providers in Web3auth](https://web3auth.io/docs/auth-provider-setup/byo-jwt-providers) |
| 201 | +- [Github OAUTH 2.0 flow](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps#web-application-flow) |
0 commit comments