Volley / Templates / Sign in with GitHub
Sign-in templateSign in with GitHub, as a sequence diagram
GitHub's OAuth web flow with the authorize parameters, the token exchange, the error GitHub returns with a 200, and the profile call, all on their arrows.
Click any arrow in the editor to see its request and response as a table or the raw body. Change the hosts, ids and fields to match your integration, then share a link or embed it in your README.
Step by step
- Your app redirects to GitHub at
/login/oauth/authorizewithclient_id,redirect_uri,scopeand a randomstate. - The user signs in and approves on GitHub.
- GitHub redirects back to your callback with a
codeand the samestate. Reject it ifstatedoes not match. - Your server exchanges the code with
POST /login/oauth/access_token, sendingAccept: application/jsonto get JSON instead of a query string. - Your server reads the profile from
GET /useron the API with the bearer token, then starts a session.
Easy to get wrong
- A bad or reused code comes back as 200 OK with an
errorfield, so checking the status alone misses it. emailis null when the user keeps it private. Ask foruser:emailand callGET /user/emails.- Without
Accept: application/jsonthe token endpoint answers form encoded.
The source
The whole diagram is this plain text. Copy it into your repo, or open it in the editor.
github-oauth.volley
title: Sign in with GitHub (OAuth app)
autonumber
order: User, Browser, App, GitHub, GitHub API
User -> Browser: Click **Sign in with GitHub**
Browser -> App: GET /auth/github
App --> Browser: 302 to GitHub
out: Redirect
Location: https://github.com/login/oauth/authorize?client_id=Ov23liExample01&redirect_uri=https%3A%2F%2Fapp.example.com%2Fauth%2Fgithub%2Fcallback&scope=read%3Auser%20user%3Aemail&state=4f1c2e9d
Browser -> GitHub: GET /login/oauth/authorize
in: Query parameters
client_id: Ov23liExample01
redirect_uri: https://app.example.com/auth/github/callback
scope: read:user user:email
state: 4f1c2e9d
...: {fab-github} User signs in and authorizes the app
GitHub --> Browser: 302 back to the app
out: Redirect
Location: https://app.example.com/auth/github/callback?code=e72e16c7e42f292c6912&state=4f1c2e9d
Browser -> App: GET /auth/github/callback?code=e72e16c7e42f292c6912&state=4f1c2e9d
note App: Reject the request if `state` does not match the value stored in the session
App -> GitHub: POST /login/oauth/access_token
in: Token request
```http
POST /login/oauth/access_token HTTP/1.1
Accept: application/json
Content-Type: application/x-www-form-urlencoded
client_id=Ov23liExample01&client_secret=<redacted>&code=e72e16c7e42f292c6912&redirect_uri=https%3A%2F%2Fapp.example.com%2Fauth%2Fgithub%2Fcallback
```
if: Code is valid
GitHub --> App: 200 OK
out: Access token
```json
{ "access_token": "gho_16C7e42F292c6912E7710c838347Ae178B4a", "token_type": "bearer", "scope": "read:user,user:email" }
```
else: Code expired or already used
GitHub --> App: 200 OK with an error
out: Error
```json
{ "error": "bad_verification_code", "error_description": "The code passed is incorrect or expired." }
```
end
note: GitHub answers a bad code with **200 OK**, so check for an `error` field instead of the status.
=: {fas-user} Reading the profile
App -> GitHub API: GET /user
in: Headers
Authorization: Bearer gho_16C7e42F292c6912E7710c838347Ae178B4a
Accept: application/vnd.github+json
X-GitHub-Api-Version: 2022-11-28
GitHub API --> App: 200 OK
out: User
```json
{ "login": "octocat", "id": 583231, "name": "The Octocat", "email": null }
```
note: `email` is null when the user keeps it private. Call `GET /user/emails` with the `user:email` scope to find the primary address.
App --> Browser: 302 to /dashboard with a session cookie
out: Response headers
Location: /dashboard
Set-Cookie: session=<redacted>; HttpOnly; Secure; SameSite=Lax