Skip to main content
Skip to content

Authorizing OAuth apps

You can enable other users to authorize your OAuth app.

Note

Consider building a GitHub App instead of an OAuth app.

Both OAuth apps and GitHub Apps use OAuth 2.0.

GitHub Apps can act on behalf of a user, similar to an OAuth app, or as themselves, which is beneficial for automations that do not require user input. Additionally, GitHub Apps use fine-grained permissions, give the user more control over which repositories the app can access, and use short-lived tokens. For more information, see Differences between GitHub Apps and OAuth apps and About creating GitHub Apps.

GitHub's OAuth implementation supports the standard authorization code grant type and the OAuth 2.0 Device Authorization Grant for apps that don't have access to a web browser.

If you want to skip authorizing your app in the standard way, such as when testing your app, you can use the non-web application flow.

To authorize your OAuth app, consider which authorization flow best fits your app.

Expiring access tokens

To enforce regular token rotation and reduce the impact of a compromised token, you can configure your OAuth app to get access tokens that expire. When your app uses access tokens that expire, you will also receive a refresh token with your access token. Both the web application flow and the device flow support expiring tokens.

The access token expires after eight hours, and the refresh token expires after six months without use. You can use the refresh token to generate a new access token and a new refresh token. For more information, see Refreshing an access token with a refresh token.

Opting in to expiring tokens at runtime

To test and gradually roll out support for expiring tokens, you can opt in to receive an expiring token and a refresh token for an individual sign-in by requesting the offline_access scope in addition to your other scopes. When you request the offline_access scope, you will receive an expiring access token and a refresh token even if your app is not configured to use expiring tokens.

If your app supports both GitHub Enterprise Server and GitHub.com, you should be prepared for the offline_access scope to have no effect, because the GitHub Enterprise Server instance may not yet support expiring tokens. In this case, you will receive a non-expiring token and no refresh token, so your app should not assume that a refresh token is always returned.

Requiring expiring tokens for your app

Once you have updated your app to use refresh tokens to handle token expiration, you can force token expiration for your app globally. This will cause all new tokens to be issued with an expiration and refresh token. Enabling this feature does not cause existing tokens to expire—they will continue to be long-lived. If you want to switch to expiring tokens, have the user sign in again. To configure this setting for your app, see Activating optional features for OAuth apps.

Web application flow

Note

If you are building a GitHub App, you can still use the OAuth web application flow, but the setup has some important differences. See Authenticating with a GitHub App on behalf of a user for more information.

The web application flow to authorize users for your app is:

  1. Users are redirected to request their GitHub identity
  2. Users are redirected back to your site by GitHub
  3. Your app accesses the API with the user's access token

1. Request a user's GitHub identity

GET https://github.com/login/oauth/authorize

This endpoint takes the following input parameters.

Query parameterTypeRequired?Description
client_idstringRequiredThe client ID you received from GitHub when you registered.
redirect_uristringStrongly recommendedThe URL in your application where users will be sent after authorization. See details below about redirect urls.
loginstringOptionalSuggests a specific account to use for signing in and authorizing the app.
scopestringContext dependentA space-delimited list of scopes. If not provided, scope defaults to an empty list for users that have not authorized any scopes for the application. For users who have authorized scopes for the application, the user won't be shown the OAuth authorization page with the list of scopes. Instead, this step of the flow will automatically complete with the set of scopes the user has authorized for the application. For example, if a user has already performed the web flow twice and has authorized one token with user scope and another token with repo scope, a third web flow that does not provide a scope will receive a token with user and repo scope. Use of the offline_access scope to get an expiring token will not alter the scope behavior—it is not tracked as a typical scope like repo or user, and will not cause additional prompts to appear if used.
statestringStrongly recommendedAn unguessable random string. It is used to protect against cross-site request forgery attacks.
code_challengestringStrongly recommendedUsed to secure the authentication flow with PKCE (Proof Key for Code Exchange). Required if code_challenge_method is included. Must be a 43 character SHA-256 hash of a random string generated by the client. See the PKCE RFC for more details about this security extension.
code_challenge_methodstringStrongly recommendedUsed to secure the authentication flow with PKCE (Proof Key for Code Exchange). Required if code_challenge is included. Must be S256 - the plain code challenge method is not supported.
allow_signupstringOptionalWhether or not unauthenticated users will be offered an option to sign up for GitHub during the OAuth flow. The default is true. Use false when a policy prohibits signups.
promptstringOptionalForces the account picker to appear if set to select_account. The account picker will also appear if the application has a non-HTTP redirect URI or if the user has multiple accounts signed in.

CORS pre-flight requests (OPTIONS) are not supported at this time.

2. Users are redirected back to your site by GitHub

If the user accepts your request, GitHub redirects back to your site with a temporary code in a code parameter as well as the state you provided in the previous step in a state parameter. The temporary code will expire after 10 minutes. If the states don't match, then a third party created the request, and you should abort the process.

Exchange this code for an access token:

POST https://github.com/login/oauth/access_token

This endpoint takes the following input parameters.

Parameter nameTypeRequired?Description
client_idstringRequiredThe client ID you received from GitHub for your OAuth app.
client_secretstringRequiredThe client secret you received from GitHub for your OAuth app.
codestringRequiredThe code you received as a response to Step 1.
redirect_uristringStrongly recommendedThe URL in your application where users are sent after authorization. We can use this to match against the URI originally provided when the code was issued, to prevent attacks against your service.
code_verifierstringStrongly recommendedUsed to secure the authentication flow with PKCE (Proof Key for Code Exchange). Required if code_challenge was sent during the user authorization. Must be the original value used to generate the code_challenge in the authorization request. This can be stored in a cookie alongside the state parameter or in a session variable during authentication, depending on your application architecture.

By default, the response takes the following form:

access_token=gho_16C7e42F292c6912E7710c838347Ae178B4a
&scope=repo%2Cgist
&token_type=bearer

You can also receive the response in different formats if you provide the format in the Accept header. For example, Accept: application/json or Accept: application/xml:

Accept: application/json
{
  "access_token":"gho_16C7e42F292c6912E7710c838347Ae178B4a",
  "scope":"repo,gist",
  "token_type":"bearer"
}
Accept: application/xml
<OAuth>
  <token_type>bearer</token_type>
  <scope>repo,gist</scope>
  <access_token>gho_16C7e42F292c6912E7710c838347Ae178B4a</access_token>
</OAuth>

If your OAuth app uses expiring access tokens, or if you requested the offline_access scope, the response also includes a refresh_token, along with the expires_in and refresh_token_expires_in values that indicate when each token expires (as seconds from the current time). For more information, see Expiring access tokens.

By default, the response takes the following form:

access_token=gho_16C7e42F292c6912E7710c838347Ae178B4a
&expires_in=28800
&refresh_token=ghr_1B4a2e77838347a7E420ce178F2E7c6912E169246c34E1ccbF66C46812d16D5B1A9Dc86A1498
&refresh_token_expires_in=15897600
&scope=repo%2Cgist
&token_type=bearer

3. Use the access token to access the API