ApiaryActive
Try: pause · settings · learn · wipe
← Community / Reading Room
O2
craft · 11 min read

OAuth 2.0 Authorization Flow

In 2023, more than 80 % of public APIs listed on major developer portals required OAuth 2.0 for authentication. The protocol’s blend of simplicity and…

Introduction

In 2023, more than 80 % of public APIs listed on major developer portals required OAuth 2.0 for authentication. The protocol’s blend of simplicity and extensibility makes it the de‑facto standard for granting third‑party applications limited, revocable access to user data—whether that data lives in a social‑media timeline, a cloud‑storage bucket, or a biodiversity‑tracking platform for bees.

For developers building web or mobile applications, the challenge is not just “how do I get a token?” but “how do I exchange that token safely, keep it out of attackers’ hands, and retire it cleanly when it’s no longer needed?” A well‑implemented OAuth 2.0 authorization flow answers those questions while preserving the user’s trust. In the context of Apiary—a hub for bee‑conservation data and self‑governing AI agents—secure token exchange protects sensitive location data of hives, pollination metrics, and AI‑driven decision models that could influence policy or land‑use planning.

This pillar article walks you through every technical decision point you’ll encounter when implementing secure token exchange in modern web apps. We’ll start from the high‑level architecture, drill down into the step‑by‑step mechanics of the Authorization Code Flow, explore extensions such as PKCE and token introspection, and finish with a concrete case study that ties the theory back to Apiary’s mission. By the end, you’ll have a reference you can return to whenever you need to design, audit, or troubleshoot an OAuth 2.0 integration.


1. The OAuth 2.0 Landscape: Why It Exists and Who Uses It

OAuth 2.0 is a delegated authorization framework defined in RFC 6749 (October 2012). Its core idea is simple: a resource owner (the user) can grant a client application limited access to a protected resource without sharing credentials. The client receives a short‑lived access token that the resource server validates on each request.

Metric (2023)Value
APIs requiring OAuth 2.0 (public)82 %
Average access‑token lifespan (seconds)3 600 – 8 640
Refresh‑token usage rate (enterprise)68 %
Reported token‑leak incidents (per 10 k apps)4.2

The protocol’s flexibility stems from four grant types (Authorization Code, Implicit, Resource Owner Password Credentials, Client Credentials) and a suite of optional extensions (PKCE, JWT‑profile, DPoP). While the Authorization Code Grant remains the most widely recommended for web and mobile apps, each grant type solves a distinct deployment scenario.

For Apiary, the typical workflow is a single‑page application (SPA) that visualizes hive health dashboards while an AI agent suggests optimal planting patterns. The SPA cannot keep a secret, so it must use the Authorization Code Flow with PKCE (Proof Key for Code Exchange). This combination mitigates the risk of interception on the public network and eliminates the need for a client secret, which would otherwise have to be embedded in JavaScript.

If you’re unfamiliar with the surrounding terminology, see our companion pages on oauth-2-0-grant-types and jwt-access-tokens for quick definitions.


2. Core Grant Types – A Quick Reference

Grant TypeIdeal ClientTypical Use‑CaseSecurity Considerations
Authorization CodeConfidential (web server) or public (SPA/mobile) with PKCEUser‑login to third‑party service (Google, Facebook)Requires redirect URI validation; CSRF protection mandatory
ImplicitPublic (SPA) – deprecated in OAuth 2.1Legacy apps that can’t handle server‑side code exchangeTokens delivered via URL fragment; higher exposure to XSS
Resource Owner Password Credentials (ROPC)Trusted first‑party appsLegacy enterprise SSO where user supplies password to appDiscouraged; bypasses MFA, exposes password to client
Client CredentialsConfidential (service‑to‑service)Backend microservice fetching its own dataNo user context; only scopes that the client is allowed

Even though the Implicit flow is still supported by some legacy APIs, the OAuth 2.1 draft (2023) recommends retiring it in favor of Authorization Code + PKCE for all browser‑based clients. The Client Credentials grant is the workhorse for server‑to‑server communication, such as an AI agent pulling aggregated pollination statistics from a protected endpoint.


3. Step‑by‑Step Walkthrough of the Authorization Code Flow (with PKCE)

Below is a concrete, numbered sequence that mirrors the actual HTTP traffic you’ll see on the wire. All URLs are illustrative; replace auth.example.com and api.example.com with your own domains.

3.1. Pre‑flight: Register the Client

  1. Create a client record in the Authorization Server (AS).
  • Assign a client_id (e.g., apiary-spa-123).
  • For public clients, omit client_secret.
  • Register redirect URIs (e.g., https://app.apiary.org/callback).
  • Optionally configure allowed scopes (hive.read hive.write ai.predict).
  1. Enable PKCE for this client. Most modern AS implementations (Keycloak, Okta, Auth0) enable it by default for public clients.

3.2. The Authorization Request

GET https://auth.example.com/authorize?
    response_type=code&
    client_id=apiary-spa-123&
    redirect_uri=https%3A%2F%2Fapp.apiary.org%2Fcallback&
    scope=hive.read%20hive.write%20ai.predict&
    state=8f3c2d1e7a&
    code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&
    code_challenge_method=S256
ParameterPurpose
response_type=codeInstructs AS to return an authorization code.
client_idIdentifies the app.
redirect_uriMust exactly match a URI registered in step 1.
scopeSpace‑delimited list of permissions requested.
stateOpaque value used to prevent CSRF; must be verified on callback.
code_challenge / code_challenge_methodPKCE values (see §4).

The code_challenge is derived from a high‑entropy random string called the code verifier (minimum 43 characters, max 128). The verifier is stored locally (e.g., in sessionStorage) until the token exchange.

3.3. User Authentication & Consent

The AS presents a login page (if the user is not already authenticated) and a consent screen listing the requested scopes. After successful login, the AS redirects the user’s browser back to the redirect_uri with two query parameters:

GET https://app.apiary.org/callback?
    code=SplxlOBeZQQYbYS6WxSbIA&
    state=8f3c2d1e7a

3.4. Token Request (Code Exchange)

The SPA now makes a POST request to the token endpoint. Because the client is public, it cannot include a secret; instead it sends the original code verifier.

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

grant_type=authorization_code&
code=SplxlOBeZQQYbYS6WxSbIA&
redirect_uri=https%3A%2F%2Fapp.apiary.org%2Fcallback&
client_id=apiary-spa-123&
code_verifier=7d9e5b9f3a2c4e6d8f1a0b7c9d2e3f4a5b6c7d8e

A successful response (JSON) looks like:

{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "8xLOxBtZp8",
  "scope": "hive.read hive.write ai.predict",
  "id_token": "eyJ0... (if OpenID Connect)"
}
  • expires_in is the number of seconds until the token is invalid (commonly 3600 s).
  • refresh_token is optional but recommended for long‑lived sessions; its lifetime is typically 30 days for SPAs, configurable per client.
  • id_token appears only when the flow is combined with OpenID Connect (OIDC) and contains user identity claims.

3.5. Using the Access Token

All subsequent API calls include the token in the Authorization header:

GET https://api.example.com/v1/hives?limit=10
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...

The Resource Server validates the token’s signature (if JWT) or introspects it via the AS’s introspection endpoint (see §5). If the token is expired, the client can use the refresh token to obtain a new access token without user interaction.


4. PKCE – Proof Key for Code Exchange

PKCE was introduced in RFC 7636 (2015) to protect the Authorization Code flow for public clients that cannot store a secret. It prevents a class of attacks known as authorization‑code interception where a malicious app on the same device steals the code from the redirect URI.

4.1. Generating the Code Verifier

function generateVerifier() {
  const array = new Uint8Array(64);
  crypto.getRandomValues(array);
  return base64urlEncode(array);
}
  • Length: 43‑128 characters (recommended 64).
  • Entropy: ≥256 bits, making brute‑force infeasible.

4.2. Deriving the Code Challenge

async function generateChallenge(verifier) {
  const digest = await crypto.subtle.digest(
    "SHA-256",
    new TextEncoder().encode(verifier)
  );
  return base64urlEncode(new Uint8Array(digest));
}
  • The challenge is a BASE64URL‑encoded SHA‑256 hash of the verifier.
  • code_challenge_method=S256 signals the server to expect a SHA‑256 hash; plain is allowed for backward compatibility but is discouraged.

4.3. Security Impact

Attack VectorWithout PKCEWith PKCE
Code interception (malicious app reads redirect URI)Attacker can exchange intercepted code for token using client secret (if any).Attacker lacks the original verifier → token exchange fails.
Authorization‑code injection (attacker injects own code)Possible if state is not verified.Still fails without matching verifier.
Replay attack (re‑use of old code)May succeed if code is still valid.Fails because verifier is one‑time use.

For Apiary’s mobile field‑data collector app, PKCE guarantees that even if a device is compromised, the attacker cannot impersonate the user without also obtaining the verifier, which never leaves the device.


5. Token Types, Storage, and Lifecycle Management

5.1. Access Tokens

  • Format: Typically a JWT (JSON Web Token) signed with RS256 or ES256.
  • Claims: iss (issuer), sub (subject), aud (audience), exp (expiration), scope.
  • Size: 1 KB on average; can be up to 2 KB for rich claims.

Because JWTs are self‑contained, the Resource Server can validate them locally (signature + expiration) without contacting the AS, reducing latency. However, revocation becomes tricky; see §7.

5.2. Refresh Tokens

  • Format: Opaque random string (e.g., 256‑bit).
  • Storage: Must be stored out‑of‑band from JavaScript to mitigate XSS. The recommended pattern for SPAs is httpOnly, Secure, SameSite=Strict cookies.
Storage OptionProsCons
sessionStorage (plain)Easy to accessVulnerable to XSS
httpOnly cookieNot readable by JSRequires CSRF protection on refresh endpoint
IndexedDB (encrypted)Persistent across tabsComplex key‑management

Apiary’s public dashboard uses httpOnly cookies for refresh tokens and in‑memory variables for access tokens, ensuring the token disappears when the page reloads.

5.3. ID Tokens (OpenID Connect)

When the flow includes OIDC (openid scope), the AS returns an ID token that contains user identity claims (email, name, picture). The SPA can verify the nonce claim to prevent replay attacks.

5.4. Token Rotation

A best practice is refresh‑token rotation: each time a refresh token is used, the AS issues a new refresh token and invalidates the old one. If an attacker steals a refresh token, the next legitimate rotation will render the stolen token useless. OAuth 2.1 draft mandates rotation for public clients.


6. Secure Token Exchange – Implementation Checklist

Below is a concise, actionable checklist that you can embed into a CI/CD pipeline or a security audit:

  1. Enforce HTTPS everywhere – TLS 1.2 minimum; HSTS header with max-age=31536000.
  2. Validate redirect_uri – exact string match; reject open redirects (/auth?next=).
  3. Generate and verify state – random 128‑bit value stored in a cookie or memory.
  4. Implement PKCE – always use S256; reject plain unless legacy support required.
  5. Store refresh tokens in httpOnly cookies with SameSite=Strict.
  6. Set Cache-Control: no-store, no-cache on token responses.
  7. Rotate refresh tokens on each use; log rotation events for forensic analysis.
  8. Apply scope least‑privilege – request only what the SPA needs (hive.read).
  9. Enable token introspection for opaque tokens (POST /introspect).
  10. Revoke tokens on logout – call POST /revocation with token and token_type_hint.

These steps directly address the most common OWASP Top 10 API Security risks (A1:2023–Broken Object Level Authorization, A5:2023–Broken Function Level Authorization).


7. Revocation, Introspection, and Token Lifecycle

7.1. Revocation Endpoint

RFC 7009 defines a revocation endpoint where a client can invalidate an access or refresh token:

POST https://auth.example.com/revoke
Content-Type: application/x-www-form-urlencoded
Authorization: Basic base64(client_id:client_secret)   # optional for public clients

token=8xLOxBtZp8&token_type_hint=refresh_token
  • Response: 200 OK with empty body (successful revocation).
  • Idempotent: Revoking an already‑revoked token yields 200 as well.

Apiary uses revocation on user‑initiated logout and also automatically revokes tokens when a hive‑owner’s account is disabled.

7.2. Introspection Endpoint

For opaque tokens, the Resource Server cannot validate locally. It calls the introspection endpoint (RFC 7662):

POST https://auth.example.com/introspect
Content-Type: application/x-www-form-urlencoded
Authorization: Basic base64(client_id:client_secret)

token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...

Successful response:

{
  "active": true,
  "client_id": "apiary-spa-123",
  "username": "alice@example.com",
  "scope": "hive.read hive.write",
  "exp": 1698765432,
  "iat": 1698761832,
  "sub": "user-42"
}

If active is false, the token is either expired, revoked, or malformed.

7.3. Token Lifetime Recommendations

TokenTypical LifetimeReason
Access token (JWT)5 – 60 minutesLimits exposure if intercepted.
Refresh token (opaque)30 days (rolling)Balances usability with security.
ID token (OIDC)1 hour (subject to re‑authentication)Mirrors access‑token lifespan.

Shorter access‑token lifetimes are especially important for AI‑driven decision APIs that may have higher value per request (e.g., recommending pesticide‑free zones). If a token is compromised, the attacker’s window is limited to a few minutes.


8. Common Pitfalls and How to Avoid Them

8.1. CSRF on the Token‑Exchange Endpoint

Even though the token endpoint is a POST, browsers will automatically include cookies (including the refresh‑token cookie) on cross‑origin requests. To prevent CSRF:

  • Require the state parameter and verify it on callback.
  • Use the SameSite=Strict attribute on refresh‑token cookies.
  • Optionally implement a double‑submit cookie pattern.

8.2. Open Redirect Vulnerabilities

If the AS accepts any redirect_uri that merely starts with a trusted domain, an attacker can craft a URL that redirects to a malicious site after the user authorizes. Mitigation:

  • Store a whitelist of exact URIs.
  • Reject any URI containing query parameters that are not part of the registered value.

8.3. Token Leakage via URL Fragments

Never place tokens in the URL fragment (#access_token=) unless you are using the Implicit flow, which is now discouraged. Fragments are logged in browser history and can be captured by malicious extensions.

8.4. Inadequate Scope Validation

APIs sometimes trust the token’s scope claim without checking the resource server’s own policy. Always enforce resource‑level access control (RBAC or ABAC) based on both token scopes and internal ACLs.

8.5. Ignoring Refresh‑Token Rotation Failures

If the AS returns an error during rotation (invalid_grant), the client should force a full re‑authentication rather than silently retrying with the old token. This prevents infinite loops and surfaces potential credential theft.


9. Real‑World Example: Securing Apiary’s Bee‑Data Portal

9.1. Scenario Overview

Apiary provides a public dashboard where citizen scientists can view live hive metrics and an AI‑powered recommendation engine that suggests planting schedules to improve pollination. The architecture consists of:

  • Frontend SPA (https://dashboard.apiary.org) built with React.
  • Authorization Server (Keycloak 22) issuing JWT access tokens.
  • Resource Server (https://api.apiary.org) exposing /v1/hives, /v1/predictions.
  • AI Agent Service (https://ai.apiary.org) that calls the Resource Server on behalf of the user.

9.2. Implementation Highlights

ComponentOAuth 2.0 FeatureImplementation Detail
SPAAuthorization Code + PKCEcode_verifier stored in sessionStorage; state stored in a SameSite cookie.
Token StoragehttpOnly Refresh CookieSet-Cookie: refresh_token=8xLOxBtZp8; HttpOnly; Secure; SameSite=Strict; Path=/auth/refresh; Max-Age=2592000
Access TokenJWT (RS256)Claims include hive_ids array (list of hives the user owns).
AI AgentClient Credentials GrantAgent uses its own client_id/client_secret to obtain a token with scope ai.predict.
RevocationLogout FlowSPA calls /auth/revoke for both access and refresh tokens; server logs revocation timestamp.
IntrospectionOpaque Token FallbackLegacy endpoint `/v1/legacy-data
Frequently asked
What is OAuth 2.0 Authorization Flow about?
In 2023, more than 80 % of public APIs listed on major developer portals required OAuth 2.0 for authentication. The protocol’s blend of simplicity and…
What should you know about introduction?
In 2023, more than 80 % of public APIs listed on major developer portals required OAuth 2.0 for authentication. The protocol’s blend of simplicity and extensibility makes it the de‑facto standard for granting third‑party applications limited, revocable access to user data—whether that data lives in a social‑media…
What should you know about 1. The OAuth 2.0 Landscape: Why It Exists and Who Uses It?
OAuth 2.0 is a delegated authorization framework defined in RFC 6749 (October 2012). Its core idea is simple: a resource owner (the user) can grant a client application limited access to a protected resource without sharing credentials . The client receives a short‑lived access token that the resource server…
What should you know about 2. Core Grant Types – A Quick Reference?
Even though the Implicit flow is still supported by some legacy APIs, the OAuth 2.1 draft (2023) recommends retiring it in favor of Authorization Code + PKCE for all browser‑based clients. The Client Credentials grant is the workhorse for server‑to‑server communication, such as an AI agent pulling aggregated…
What should you know about 3. Step‑by‑Step Walkthrough of the Authorization Code Flow (with PKCE)?
Below is a concrete, numbered sequence that mirrors the actual HTTP traffic you’ll see on the wire. All URLs are illustrative; replace auth.example.com and api.example.com with your own domains.
References & sources
  1. Apiary Reading Room — Open, cited knowledge base — funded to keep bee & practical research free.
From the Apiary Reading Room. Opinion & editorial — not financial advice. We don't overclaim.
More from the Reading Room