Authorization Code Flow
The Authorization Code flow is the most widely recommended OAuth2 grant type for any client that can direct a user's browser to an authorization server and receive a redirect back — single-page apps, native/mobile apps, and traditional server-rendered web apps.
Rather than returning tokens directly to the browser (as the now-deprecated Implicit flow did), the client first receives a short-lived, single-use code. That code is then exchanged for tokens over a separate back-channel request. This extra hop keeps tokens out of the browser history/URL and gives the authorization server a chance to bind the exchange to the client that started it.
TIP
Public clients (SPAs, native/mobile apps) can't safely hold a client_secret, since anything shipped to a device or browser can be extracted. PKCE closes this gap by having the client prove, at token-exchange time, that it's the same party that started the flow — without ever needing a static secret. It's on by default for every AuthorizationCodeFlow in this SDK.
Participants
- Resource Owner: the user completing sign-in
- Client: your application
- Authorization Server: authenticates the user and issues tokens
- Resource Server: the API the client ultimately wants to call
How It Works
- The client generates a
statevalue (and, for OIDC, anonce), along with a PKCEcode_verifierand its derivedcode_challenge. - The client redirects the user's browser to the authorization server's
/authorizeendpoint, includingclient_id,redirect_uri,scope,state, andcode_challenge. - The user authenticates with the authorization server and approves the request (if a consent screen is required).
- The authorization server redirects the browser back to the client's
redirect_uriwith an authorizationcodeand the originalstate. - The client verifies the returned
statematches what it sent in step 1, protecting against CSRF. - The client exchanges the
code— along with the original PKCEcode_verifier— for tokens via aPOSTto the authorization server's/tokenendpoint. - The authorization server validates the
client_id,code, and PKCEcode_verifier, then returns an access token (plus an ID token and/or refresh token, depending on the requested scopes). - The client uses the access token to call the resource server on the user's behalf.
Security Considerations
statemust be unique per authorization request and verified on redirect — it's what stops an attacker from tricking a user into completing someone else's flow.nonce(OIDC) is echoed back inside the ID token itself, protecting against replay of a previously issued token.- PKCE protects the
code-for-token exchange even if the authorizationcodeis intercepted in transit, since only the party holding the originalcode_verifiercan redeem it. - DPoP goes a step further than PKCE by binding the issued tokens to a private key generated on the client. Every request made with a DPoP-bound token — the token exchange itself, and every subsequent call to a resource server — must be accompanied by a fresh proof signed with that key. A leaked or intercepted access/refresh token is useless to an attacker without the private key, which never leaves the client.
- Because everything relies on the client still having its original
state/code_verifier, that data has to survive the full round trip to the authorization server and back — including a full-page redirect on the web.
TIP
All of these security controls are enabled by default within the Okta Client JavaScript ecosystem with the exception of DPoP, which is easily configurable
See Also
- Okta Documentation: Concepts · Implementation Guide
- oauth.net: Authorization Code Grant Type
- RFC 6749, §1.3.1