PureTools

OAuth 2.0 Flows: Which One Do You Need?

PureTools Team· 9 min read
OAuth 2.0 Flows: Which One Do You Need?

OAuth 2.0: Let Users Log In Without Storing Passwords

OAuth 2.0 is a delegation protocol. Instead of your app collecting and storing user passwords, you redirect them to Google/GitHub/etc., they authenticate there, and come back with a token. Your app never sees the password.

Key Terms

TermMeaning
Resource OwnerThe user
ClientYour application
Authorization ServerGoogle, GitHub, Auth0 — who authenticates the user
Resource ServerThe API that has the user's data
Access TokenShort-lived token to access APIs
Refresh TokenLong-lived token to get new access tokens
ScopeWhat permissions the token grants (e.g., read:email)

Flow 1: Authorization Code + PKCE (Recommended)

For web apps, SPAs, mobile apps. The most secure flow for user-facing applications.

1. Your app redirects the user to the authorization server:
   GET https://auth.example.com/authorize?
     response_type=code&
     client_id=YOUR_CLIENT_ID&
     redirect_uri=https://yourapp.com/callback&
     scope=openid email profile&
     state=random_csrf_token&
     code_challenge=SHA256(code_verifier)&
     code_challenge_method=S256

2. User logs in and consents

3. Auth server redirects back with a code:
   https://yourapp.com/callback?code=AUTH_CODE&state=random_csrf_token

4. Your server exchanges the code for tokens:
   POST https://auth.example.com/token
   Content-Type: application/x-www-form-urlencoded

   grant_type=authorization_code&
   code=AUTH_CODE&
   redirect_uri=https://yourapp.com/callback&
   client_id=YOUR_CLIENT_ID&
   code_verifier=ORIGINAL_CODE_VERIFIER

5. Response:
   {
     "access_token": "eyJ...",
     "token_type": "Bearer",
     "expires_in": 3600,
     "refresh_token": "abc..."
   }

PKCE (Proof Key for Code Exchange) prevents authorization code interception. It's required for SPAs and mobile apps, recommended for all apps.

Flow 2: Client Credentials

For server-to-server communication. No user involved.

POST https://auth.example.com/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&
client_id=YOUR_CLIENT_ID&
client_secret=YOUR_CLIENT_SECRET&
scope=read:data

Response:
{
  "access_token": "eyJ...",
  "token_type": "Bearer",
  "expires_in": 3600
}

Use this when your backend needs to call another API without user context (cron jobs, microservices).

Which Flow to Use

Application TypeFlowNotes
Web app (server-rendered)Authorization Code + PKCEServer can keep client_secret
SPA (React, Vue)Authorization Code + PKCENo client_secret (public client)
Mobile appAuthorization Code + PKCEUse deep links for redirect
Server-to-serverClient CredentialsNo user interaction
CLI toolDevice CodeUser authorizes on another device

Deprecated Flows (Don't Use)

  • Implicit Flow: Tokens in the URL fragment. Deprecated — use Authorization Code + PKCE instead.
  • Resource Owner Password Credentials: App collects username/password directly. Defeats the purpose of OAuth.

Common Implementation (Next.js + NextAuth)

// app/api/auth/[...nextauth]/route.ts
import NextAuth from 'next-auth';
import GitHubProvider from 'next-auth/providers/github';
import GoogleProvider from 'next-auth/providers/google';

export const { handlers, auth } = NextAuth({
  providers: [
    GitHubProvider({
      clientId: process.env.GITHUB_CLIENT_ID!,
      clientSecret: process.env.GITHUB_CLIENT_SECRET!,
    }),
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    }),
  ],
});

Decode your tokens: JWT Decoder — inspect OAuth access tokens and ID tokens.