Skip to main content

Command Palette

Search for a command to run...

Authentication Flows: Choosing the Right One

A practical guide to understanding OAuth2 and OIDC flows—and how to choose the right one for your app.

Updated
8 min read
Authentication Flows: Choosing the Right One
N
Senior-level Fullstack Web Developer with 10+ years experience, including 2 years of Team Lead position. Specializing in responsive design and full-stack web development across the Vue.js and .NET ecosystems. Skilled in Azure/AWS cloud infrastructure, focused on DevOps techniques such as CI/CD. Experienced in system design, especially with software architecture patterns such as microservices, BFF (backend-for-frontend). Hands-on with Agile practices in team leading, and AI-assisted coding.

Series: Web Authentication Demystified — From Concepts to Real-World
ARC 1 — FOUNDATIONS OF USER AUTHENTICATION
Previous: Understanding OAuth2 & OpenID Connect (OIDC)
Next: Sessions vs Token-Based Authentication

Modern web and mobile applications rely on OAuth2 and OpenID Connect (OIDC) flows to authenticate users and obtain tokens securely. But each flow was designed for a specific scenario, and choosing the wrong one can introduce both security and UX issues.

This article provides a grounded walk-through of the major authentication flows, explains how they work, and gives you a practical decision-making framework for selecting the right flow for web apps, SPAs, mobile apps, and backend services.


Why Authentication Flows Exist

Different environments have different constraints: browsers expose tokens to JavaScript, mobile apps can't keep secrets, servers can, and IoT devices may have no keyboard at all. The OAuth2/OIDC ecosystem solves this through a standardized set of flows that shift responsibility between client, user, and server in predictable ways.

Think of flows as recipes for obtaining tokens safely under specific conditions.

1. OAuth2 Authorization Code Flow (Classic Server-Side Web Apps)

The Authorization Code Flow is the most widely used and secure flow when the client has a backend server capable of storing secrets.

How It Works (Simple Diagram)

Browser → App Server → Authorization Endpoint
                                ↓ (user logs in)
Browser ← Redirect with Authorization Code
Browser → App Server → Token Endpoint (exchange code → tokens)
App Server → Resource/API (use access token)

Key Idea

The authorization code is delivered to the backend, not directly to the browser.
This prevents tokens from being exposed to client-side scripts.

Pros

  • Very secure (tokens kept server-side)

  • Works well with traditional web apps

  • Perfect for server-rendered frameworks (PHP, Rails, Django, ASP.NET)

Cons

  • Requires backend infrastructure

  • Not suitable for SPAs without PKCE

Best For

  • Traditional websites

  • Applications with server-rendered pages

  • Backends that keep secrets securely


2. Authorization Code + PKCE (For SPAs & Mobile)

PKCE (Proof Key for Code Exchange) was created because SPAs and mobile apps cannot safely store client secrets.

PKCE adds a cryptographic challenge that proves the client that began the flow is the one completing it.

How It Works

SPA/Mobile → Create code_verifier → Hash → code_challenge
SPA → Authorization Endpoint + code_challenge
                       ↓
Redirect back with Authorization Code
SPA → Token Endpoint + code_verifier
Token issued only if verifier matches the challenge

Why PKCE Matters

If an attacker intercepts the authorization code, they cannot exchange it without the secret code_verifier.

Pros

  • Highly secure, even for public clients

  • Works for mobile apps and SPAs

  • Recommended by all providers (Google, Auth0, Azure AD)

Cons

  • Requires careful handling of tokens in the browser

  • Still vulnerable if tokens are stored incorrectly (e.g., localStorage)

Best For

  • Single Page Applications (React, Vue, Angular)

  • Native mobile apps (iOS, Android)

  • Any public client that cannot hold secrets


3. Implicit Flow (Obsolete — Do Not Use)

The implicit flow was originally designed for SPAs because they couldn't perform a secure back-channel request.
Tokens were returned directly in the browser URL hash, making them easy to steal.

Why It’s Obsolete

  • No ID token validation

  • Tokens exposed to the browser via URL

  • Vulnerable to replay and leakage via referrer headers

  • All major providers now recommend Authorization Code + PKCE instead

Best For

  • Nothing today. Avoid it completely.

4. Client Credentials Flow (Machine-to-Machine)

This flow is for backend services, not users.
It issues an access token based on the app’s identity, not a person's.

How It Works

Server A → Token Endpoint (client_id + client_secret)
Token → Server A → Server B (API)

Pros

  • Simple and secure for server-to-server communication

  • No user interaction

  • Secret stays on backend

Cons

  • Cannot represent a real user

  • Only suitable for service authentication

Best For

  • Microservices calling each other

  • Background jobs

  • Cron jobs accessing APIs

  • Internal service accounts


5. Device Code Flow (For Devices With No Keyboard)

Used by:

  • Smart TVs

  • Consoles

  • IoT devices

Where typing a password is painful.

How It Works

Device → Gets user_code + verification URL
User → Browser → verification URL → login
Device polls → Token issued once login completed

Pros

  • Great UX for limited input devices

  • Secure — device never sees credentials

Cons

  • Requires polling

  • More complex to implement

Best For

  • TVs, set-top boxes

  • Smart appliances

  • CLI tools


6. Resource Owner Password Flow (Obsolete & Dangerous)

This flow asks the user to give their password directly to the application, which then exchanges it for tokens.

Why It’s Bad

  • Completely breaks security boundaries

  • The client (which may be malicious) gains the user’s password

  • No MFA support

  • Impossible to enforce security policies

Best For

  • Absolutely nothing. Avoid it entirely in modern systems.

7. Refresh Token Flow (Token Renewal)

Not a standalone authentication flow, but a mechanism to renew access tokens without re-authenticating the user.

How It Works

App → Token Endpoint (refresh_token)
IdP → Issues new access token (and sometimes new refresh token)

Pros

  • Enables long-lived sessions

  • Reduces need for the user to log in repeatedly

  • Works across web, mobile, and backend apps

Cons

  • Must be stored securely

  • If leaked, attacker can mint new access tokens

Best For

  • SPAs & mobile apps (with secure storage)

  • Server-side apps needing long sessions


8. Hybrid OIDC Flow (Legacy)

The Hybrid Flow is an OpenID Connect flow that combines elements of both:

  • Authorization Code Flow (secure, backend-driven, uses a code exchange)

  • Implicit Flow (immediate delivery of ID tokens to the front-end)

Pros

  • Front-end gets user identity immediately (good for UX)

  • Backend still uses secure code exchange

  • Supports both old browsers and complicated enterprise infrastructure

Cons

  • ID token exposed via front-channel (less secure)

  • Complex implementation

  • Deprecated in many modern SPA patterns

  • PKCE-based Auth Code Flow solves most of its use cases more safely

When to Use

  • you maintain a legacy OIDC integration

  • you need immediate ID token delivery for UI before backend processing

  • your IdP or enterprise ecosystem requires Hybrid Flow

  • you have a multi-page app that renders UI before your backend finishes token exchange

Today, most apps prefer Authorization Code + PKCE instead.


Choosing the Right Flow: A Decision Framework

Here's a practical, no-nonsense guide:

1. Are you building a server-side web app (PHP, Rails, Django, ASP.NET)?

Use Authorization Code Flow (no PKCE)
Backend holds tokens — safest option.

2. Are you building a SPA (React, Vue, Angular)?

Use Authorization Code + PKCE
Never use implicit flow.

3. Are you building a mobile app (iOS, Android)?

Use Authorization Code + PKCE
Store tokens securely (Keychain / Secure Enclave).

4. Are you building microservices / backend-to-backend authentication?

Use Client Credentials Flow
No user involved.

5. Are you building apps for TVs or IoT devices?

Use Device Code Flow

6. Are you thinking about Resource Owner Password Flow?

Stop. Don’t.
Use OIDC-based flows instead.

7. Do you need long-lived sessions?

Use Refresh Token Flow
Rotate refresh tokens regularly.

Real Use Case Decision Flow (based on my experience)

Use Case:

A teacher at a public-sector education institute logs into a 3rd-party educational web app using their government-issued identity (via a central IdP). The app is a traditional server-rendered web application.

Step 1 — Is the app a traditional server-side web application?

Yes.
The 3rd-party education web app is server-rendered, has a backend, and can store secrets.

➡️ Candidate flows:

  • Authorization Code Flow

  • Authorization Code + PKCE

  • Hybrid OIDC

  • (Implicit Flow excluded — obsolete)

  • (Password Flow excluded — insecure)

Step 2 — Can the app securely store secrets on the backend?

Yes.
The 3rd-party platform has a backend server (PHP/Yii in my implementation).

➡️ Authorization Code Flow is strongly suitable.

Step 3 — Do you need strong protection against code interception (PKCE)?

Not required.
PKCE is essential for public clients like SPAs or mobile apps, not for confidential server-side applications that can safely store secrets.

➡️ PKCE is optional (useful but not necessary).

Step 4 — Does the frontend require immediate ID Token access before the backend finishes the code exchange?

No.
Traditional server-rendered apps don’t need instant client-side identity for reactive UI.

➡️ Hybrid Flow is unnecessary.

Step 5 — Is the user a real human who must authenticate interactively?

Yes — the teacher must log in manually using their government identity.

➡️ Client Credentials Flow is invalid (machine-to-machine only).
➡️ Device Code Flow is irrelevant (not a TV/IoT device).

Step 6 — Are refresh tokens needed for long session continuity?

Possibly yes.
The backend can store and rotate refresh tokens securely, extending user sessions without requiring re-login to the IdP.

➡️ Refresh Token Flow may be used alongside Authorization Code Flow.

Final Decision: The Correct Flow for the Scenario

Use the OAuth2 / OIDC Authorization Code Flow (with optional refresh tokens)
with:

  • response_type=code

  • Standard OIDC scopes (openid email profile)

  • Backend-only token storage

  • Refresh token rotation for persistent login

  • JWT validation through the IdP’s JWKS endpoint

This is the industry-standard choice for:

  • Server-rendered web apps

  • Confidential clients capable of storing secrets

  • Human users logging in interactively

  • Integrations with enterprise/government IdPs

  • Secure token handling on backend servers

Optional Enhancements:

  • Add PKCE if the IdP or regulation framework requires it

  • Use Refresh Tokens to avoid frequent re-logins

  • Use OIDC to retrieve ID Tokens for identity mapping

  • Use scopes (openid, email, profile) to control access


Final Thoughts

OAuth2 and OIDC offer a range of flows because authentication isn’t one-size-fits-all. By choosing the right flow, you ensure:

  • Better security

  • A smoother user experience

  • Fewer vulnerabilities

  • Cleaner architecture

Now that we’ve explored authentication flows, the next article will dive into how sessions and token-based authentication compare, and how real-world applications bridge the two models.

Web Authentication Demystified — From Concepts to Real-World

Part 10 of 14

This series breaks down modern web authentication, from core concepts like OAuth, OIDC, and tokens to real implementation details. You’ll learn how the pieces fit together and see how a production-ready system is built and secured.

Up next

Understanding OAuth2 & OpenID Connect (OIDC)

A clear guide to how OAuth2 and OIDC work together to provide modern authentication and secure delegated access.