OAuth2 Flows Reference

OAuth2 flows reference — Authorization Code, Client Credentials, PKCE, Implicit. When to use each flow, token types, and real request/response examples.

7 min read

OAuth 2.0 is an authorization framework that enables applications to obtain limited access to user accounts on an HTTP service, such as Facebook or Google, without exposing the user’s password.

Installation

OAuth 2.0 is a protocol, not a tool to be installed. You interact with OAuth 2.0 through libraries and frameworks within your programming language or by directly making HTTP requests to authorization servers.

Core Concepts

  • Resource Owner: The user who owns the data and grants permission to access it.
  • Client: The application requesting access to the Resource Owner’s data.
  • Authorization Server: The server that authenticates the Resource Owner and issues access tokens after obtaining authorization.
  • Resource Server: The server hosting the protected resources, capable of accepting and responding to protected resource requests using access tokens.
  • Resource Owner Password Credentials: The Resource Owner’s username and password, used directly by the client to obtain an access token. (Not recommended for most third-party applications).
  • Authorization Grant: A credential representing the Resource Owner’s authorization to access resources server.
  • Access Token: A credential used by the client to make authorized requests to the Resource Server.
  • Refresh Token: A credential used to obtain a new access token when the current one expires.
  • Scope: Defines the level of access the client is requesting. For example, read_profile or write_posts.
  • Client ID: A unique identifier for the client application, issued by the Authorization Server.
  • Client Secret: A secret string used by the client to authenticate with the Authorization Server.

Flows / Usage

Authorization Code Grant

This is the most common and secure flow for web applications.

  1. Client requests authorization from Resource Owner: The client redirects the Resource Owner’s browser to the Authorization Server’s /authorize endpoint.

    GET https://authorization-server.com/oauth/authorize?
        response_type=code&
        client_id=YOUR_CLIENT_ID&
        redirect_uri=https://your-app.com/callback&
        scope=read_profile%20write_posts&
        state=a_random_string_to_prevent_csrf
    
    • response_type=code: Specifies that the client is requesting an authorization code.
    • client_id: The unique identifier for your application.
    • redirect_uri: The URI where the Authorization Server will redirect the Resource Owner back to after authorization. Must be pre-registered.
    • scope: A space-separated list of permissions the client is requesting.
    • state: An opaque value used by the client to maintain state between the request and callback.
  2. Resource Owner authorizes the client: The user logs in to the Authorization Server and approves (or denies) the requested permissions.

  3. Authorization Server redirects back to Client with Authorization Code: If authorized, the Authorization Server redirects the Resource Owner’s browser back to the redirect_uri with an authorization code and the state parameter.

    GET https://your-app.com/callback?
        code=AUTHORIZATION_CODE_FROM_SERVER&
        state=a_random_string_to_prevent_csrf
    
  4. Client exchanges Authorization Code for Access Token: The client (server-side) makes a direct request to the Authorization Server’s /token endpoint to exchange the authorization code for an access token.

    POST https://authorization-server.com/oauth/token
    Content-Type: application/x-www-form-urlencoded
    
    grant_type=authorization_code&
    code=AUTHORIZATION_CODE_FROM_SERVER&
    redirect_uri=https://your-app.com/callback&
    client_id=YOUR_CLIENT_ID&
    client_secret=YOUR_CLIENT_SECRET
    
    • grant_type=authorization_code: Specifies that you are exchanging an authorization code.
    • code: The authorization code received in the previous step.
    • redirect_uri: Must match the one used in the /authorize request.
    • client_id: Your application’s client ID.
    • client_secret: Your application’s client secret.
  5. Authorization Server responds with Access Token: The Authorization Server validates the code and client credentials and responds with an access token (and optionally a refresh token).

    {
        "access_token": "ACCESS_TOKEN_VALUE",
        "token_type": "Bearer",
        "expires_in": 3600,
        "refresh_token": "REFRESH_TOKEN_VALUE",
        "scope": "read_profile write_posts"
    }
    
  6. Client uses Access Token to access Resource Server: The client includes the access_token in the Authorization header of requests to the Resource Server.

    GET https://resource-server.com/api/user/profile
    Authorization: Bearer ACCESS_TOKEN_VALUE
    

This flow is for single-page applications (SPAs) where a client secret cannot be kept secure. It’s less secure as the access token is returned directly in the URL fragment.

  1. Client requests authorization from Resource Owner: Similar to Authorization Code Grant, but response_type is token.

    GET https://authorization-server.com/oauth/authorize?
        response_type=token&
        client_id=YOUR_CLIENT_ID&
        redirect_uri=https://your-spa.com/callback&
        scope=read_profile&
        state=a_random_string_to_prevent_csrf
    
  2. Resource Owner authorizes the client: User logs in and approves.

  3. Authorization Server redirects back to Client with Access Token: The Authorization Server redirects the Resource Owner’s browser back to the redirect_uri with the access_token in the URL fragment.

    GET https://your-spa.com/callback#
        access_token=ACCESS_TOKEN_VALUE&
        token_type=Bearer&
        expires_in=3600&
        scope=read_profile&
        state=a_random_string_to_prevent_csrf
    
  4. Client uses Access Token to access Resource Server: The SPA extracts the access_token from the URL fragment and uses it in requests to the Resource Server.

    GET https://resource-server.com/api/user/profile
    Authorization: Bearer ACCESS_TOKEN_VALUE
    

The client collects the Resource Owner’s username and password and sends them directly to the Authorization Server to get an access token. Only use this if you are the resource owner and the client is your own application.

  1. Client requests Access Token with User Credentials:

    POST https://authorization-server.com/oauth/token
    Content-Type: application/x-www-form-urlencoded
    
    grant_type=password&
    username=USER_EMAIL@example.com&
    password=USER_PASSWORD&
    client_id=YOUR_CLIENT_ID&
    client_secret=YOUR_CLIENT_SECRET&
    scope=read_profile
    
    • grant_type=password: Specifies you are using user credentials.
    • username: The Resource Owner’s username.
    • password: The Resource Owner’s password.
    • client_id, client_secret: Your application’s credentials.
    • scope: Requested permissions.
  2. Authorization Server responds with Access Token: The Authorization Server validates the credentials and responds with an access token.

    {
        "access_token": "ACCESS_TOKEN_VALUE",
        "token_type": "Bearer",
        "expires_in": 3600,
        "scope": "read_profile"
    }
    
  3. Client uses Access Token to access Resource Server: Same as step 6 in Authorization Code Grant.

Client Credentials Grant (Machine-to-Machine)

This flow is used for clients accessing their own resources, not on behalf of a user.

  1. Client requests Access Token using its own credentials:

    POST https://authorization-server.com/oauth/token
    Content-Type: application/x-www-form-urlencoded
    
    grant_type=client_credentials&
    client_id=YOUR_CLIENT_ID&
    client_secret=YOUR_CLIENT_SECRET&
    scope=read_api_data
    
    • grant_type=client_credentials: Specifies you are using client credentials.
    • client_id, client_secret: Your application’s credentials.
    • scope: Requested permissions for the client itself.
  2. Authorization Server responds with Access Token:

    {
        "access_token": "ACCESS_TOKEN_VALUE",
        "token_type": "Bearer",
        "expires_in": 3600,
        "scope": "read_api_data"
    }
    
  3. Client uses Access Token to access Resource Server: Same as step 6 in Authorization Code Grant.

Common Patterns

  • Handling Token Expiration and Refresh: When an access_token expires (indicated by a 401 Unauthorized response from the Resource Server), use the refresh_token to obtain a new access_token.

    POST https://authorization-server.com/oauth/token
    Content-Type: application/x-www-form-urlencoded
    
    grant_type=refresh_token&
    refresh_token=REFRESH_TOKEN_VALUE&
    client_id=YOUR_CLIENT_ID&
    client_secret=YOUR_CLIENT_SECRET&
    scope=read_profile  // Optional: can request a subset of original scopes
    
  • Validating Access Tokens: Many APIs provide an endpoint to introspect an access token, or the token itself might be a JWT (JSON Web Token) that can be decoded and validated locally (check signature, expiration, issuer, audience).

    • Introspection Endpoint Example:

      POST https://authorization-server.com/oauth/introspect
      Content-Type: application/x-www-form-urlencoded
      
      token=ACCESS_TOKEN_VALUE&
      client_id=YOUR_CLIENT_ID&
      client_secret=YOUR_CLIENT_SECRET
      

      Response indicates if the token is active, its scopes, etc.

    • JWT Decoding (Conceptual - uses a library): If your access_token is a JWT, you can use a library to decode its header and payload to inspect its contents (e.g., expiration exp, issuer iss, audience aud).

  • Implementing CSRF Protection with state: When initiating the authorization flow, generate a unique, unguessable random string and store it in the user’s session. Compare this stored state with the state parameter received in the callback URL to ensure the request originated from your application.

Gotchas

  • redirect_uri Mismatch: The redirect_uri provided in both the authorization request and the token exchange request must exactly match a pre-registered URI with the Authorization Server. Even minor differences (e.g., trailing slash, http vs https) will cause failure.
  • Client Secret Exposure: Never embed your client_secret in client-side JavaScript or mobile applications. Use flows like Authorization Code Grant with PKCE, or the Resource Owner Password Credentials Grant (with extreme caution and only for first-party apps).
  • Token Storage: Securely store access and refresh tokens. For web apps, consider HttpOnly cookies for refresh tokens and in-memory storage or secure local storage for access tokens.
  • Scope Validation: The Authorization Server may issue tokens with fewer scopes than requested. Always check the scope returned in the token response and validate it before performing actions.
  • Authorization Code Expiration: Authorization codes are short-lived (typically minutes) and can only be used once.
  • token_type: Always check the token_type in the token response. Bearer is common, meaning the token is presented directly in the Authorization: Bearer <token> header. Other types might exist.
  • PKCE (Proof Key for Code Exchange): For public clients (like SPAs and mobile apps) using the Authorization Code Grant, PKCE is highly recommended to prevent authorization code interception attacks. It involves generating a code_verifier and code_challenge during the authorization request.