Implicit flow
This page helps you keep an old browser app that uses the implicit flow working, and move it off.
The implicit flow skips the authorization code. The browser comes back from the auth server with the tokens themselves, after the # in your redirect URI, and your app’s JavaScript reads them from there. It was made for browser apps from before they could call a token endpoint on another origin. They all can now, so the only reason left to use it is an app you can’t change yet.
When to turn it on
Section titled “When to turn it on”Turn it on only for an app that speaks nothing but the implicit flow and that you can’t update yet, and only for that app’s client, while you move it off. Leave the global setting off, so no other client gets it by accident.
Turn it on for one client
Section titled “Turn it on for one client”-
In the admin console, open Admin, Clients and click Manage beside your app’s client.
-
On OAuth2 flows, under Legacy flows (deprecated in OAuth 2.1), set Implicit flow to Enabled, and click Save.
-
On Redirect URIs, add the page that receives the tokens, such as
https://app.example.com/callback, and click Save. -
Make a new random
stateandnonce, keep them, and send the browser to the authorization endpoint withresponse_type=id_token token:GET /auth/authorize?client_id=legacy-spa&redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback&response_type=id_token%20token&scope=openid%20email&state=af0ifjsldkj&nonce=n-0S6_WzA2Mj HTTP/1.1Host: auth.example.com -
The user signs in, and the browser comes back with the tokens after the
#:HTTP/1.1 302 FoundLocation: https://app.example.com/callback#access_token=eyJhbGciOiJSUzI1NiIs...&token_type=Bearer&expires_in=300&id_token=eyJhbGciOiJSUzI1NiIs...&scope=openid+email&state=af0ifjsldkj -
Check that
stateis the one you kept. Check the ID token as a web app does,nonceincluded, and check itsat_hashagainst the access token. Then replace the address in the browser’s history with one that has no#part, so the tokens don’t stay there.
Implicit flow on the OAuth2 flows tab has three choices: Enabled, Disabled, or inherit the global Implicit flow enabled under Admin, General, which is off in a new install.
Response types
Section titled “Response types”response_type |
What comes back |
|---|---|
id_token token |
An ID token and an access token. The ID token carries at_hash, a hash of the access token. |
id_token |
An ID token only |
token |
An access token only |
token id_token works too, since the order doesn’t matter. A request asking for an ID token needs openid in its scope and a nonce, as OpenID Connect Core 1.0 section 3.2.2.1 requires, or it’s refused with invalid_request.
Ask for id_token token when your app needs an access token. at_hash ties the access token to an ID token that carries your nonce, which is the one way your app can tell the access token was issued for its own request. With id_token alone there’s no access token to call UserInfo with, so the user’s claims reach your app only when Include OpenID Connect claims in the ID token is on. It’s on in a new install. See Scopes.
What comes back
Section titled “What comes back”The browser comes back to your redirect URI with these parameters after the #:
| Parameter | When |
|---|---|
access_token |
response_type has token |
token_type |
With access_token. It’s Bearer. |
expires_in |
With access_token: its lifetime in seconds, the client’s token expiration or else the global one, 300 in a new install |
id_token |
response_type has id_token |
scope |
The scopes granted, which can be fewer than your app asked for |
state |
When your app sent one, unchanged |
There’s never a refresh token: RFC 6749 section 4.2.2 forbids one, so offline_access is dropped from the scope, as OpenID Connect Core 1.0 section 11 asks. When the access token expires, send the browser back to the auth server. A user whose session is still valid isn’t asked for their password again.
With response_mode=form_post, the same parameters are posted to your redirect URI by a page that sends a form on its own. response_mode=query is refused with invalid_request, since tokens never travel in the query. Errors come back the same way as tokens, after the # or posted: error, error_description, and state when your app sent one.
What the auth server checks
Section titled “What the auth server checks”The implicit flow goes through the same authorization endpoint as the authorization code flow, with the same checks, sign-in, ACR levels, consent and prompt. These rules are its own:
- The client needs the implicit flow on, or the request is refused with
unauthorized_client. It doesn’t need the authorization code flow on. - The redirect URI matches exactly. A loopback redirect URI’s port isn’t ignored, as it is for the authorization code flow, since tokens rather than a code would go to whatever program is listening there.
- PKCE doesn’t apply. There’s no code to tie it to, and a
code_challengeis ignored. - The setting is read again just before the tokens are issued, so a sign-in under way when an administrator turns the flow off ends with
unauthorized_clientand no tokens. - The tokens are tied to the user’s session, which must still be valid when they’re issued. Each issue leaves a
token_issued_implicit_responseentry in the audit log.
Why it’s deprecated
Section titled “Why it’s deprecated”Move to the authorization code flow
Section titled “Move to the authorization code flow”-
On the client’s Authentication tab, choose Public client if it isn’t one, click Save, and confirm with Yes. Your app runs in the browser, so it can’t keep a secret.
-
On OAuth2 flows, turn on Authorization code with PKCE, and click Save.
-
On Web origins, add your app’s origin, such as
https://app.example.com, so the browser lets it call the token endpoint. -
Change your app to send
response_type=codewith a PKCE challenge, and redeem the code at the token endpoint. Add sign-in to a SPA or mobile app walks through it. Your app gets refresh tokens now too. -
Once no user is on the old version, set Implicit flow to Disabled.