Volley / Templates / Sign in with GitHub

Sign-in template

Sign 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.

Numbered sequence diagram of Sign in with GitHub across User, Browser, App, GitHub and GitHub API: authorize redirect, callback with a code, token exchange with success and error branches, GET /user, and a session cookie.

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

  1. Your app redirects to GitHub at /login/oauth/authorize with client_id, redirect_uri, scope and a random state.
  2. The user signs in and approves on GitHub.
  3. GitHub redirects back to your callback with a code and the same state. Reject it if state does not match.
  4. Your server exchanges the code with POST /login/oauth/access_token, sending Accept: application/json to get JSON instead of a query string.
  5. Your server reads the profile from GET /user on 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 error field, so checking the status alone misses it.
  • email is null when the user keeps it private. Ask for user:email and call GET /user/emails.
  • Without Accept: application/json the 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

Related

Make this Sign in with GitHub diagram yours.

Open it in the editor, change it to match your integration and share the link. Free, with no account.