OIDC Grant Types in Okta
A plain-English guide to every way an application can ask Okta for tokens: what each grant type does, when to use it, which ones to avoid, and how to keep all of them safe in production.
Imagine you walk up to the front desk of a big office building. The guard does not hand you the master key to every room. Instead, the guard checks who you are, asks why you are here, and gives you a visitor badge that opens only the doors you need, for only as long as you need them. Nobody argues about this. It is just how safe buildings work.
Modern software works the same way. When an app wants to read your calendar, call a company API, or log you in, it should never hold your password forever. It should receive a small, temporary pass called a token. The question is: how does the app get that pass? The answer is a grant type, and each grant type is a different “front desk procedure” for different kinds of visitors.
Okta is one of the most widely used identity platforms in the world, and it supports many grant types. Picking the wrong one is one of the most common reasons teams end up with security holes, broken logins, or confusing error messages. By the end of this guide you will know every major grant type Okta offers, what problem each one solves, and exactly how to choose between them without guessing.
WWhat Is a Grant Type?
Before we meet Okta, we need three short ideas: OAuth 2.0, OpenID Connect, and the word “grant.”
OAuth 2.0: The Permission Framework
OAuth 2.0 is an industry standard that lets one application get limited access to something on behalf of a person or on behalf of itself, without ever seeing the person’s password. It was designed because sharing passwords with every app is a terrible idea. If ten apps know your password, a leak at any one of them exposes you everywhere.
OAuth 2.0 does not log anyone in. It only answers the question “is this app allowed to do this thing?” The answer comes back as an access token.
OpenID Connect (OIDC): The Identity Layer
OpenID Connect, usually shortened to OIDC, is a thin layer built on top of OAuth 2.0. It adds the missing piece: proof of who the person is. OIDC introduces the ID token, a signed document that says “this is user Priya, she signed in at 9:02 AM, using this method, and this token was meant for this app.”
So OAuth 2.0 is about permission and OIDC is about identity. Okta speaks both at the same time, which is why people say “OIDC in Okta” when they mean the whole bundle.
What a “Grant” Actually Is
In OAuth, a grant is the proof that an app is allowed to ask for tokens. A grant type is the specific recipe used to show that proof and trade it for tokens. Different recipes exist because different apps live in different worlds. A website running on a secure server is not like a phone app, and neither is like a smart TV with no keyboard, or a background job that runs at 3 AM with nobody around.
Think of grant types as different ways to get into a concert. Some people buy a ticket online and show a QR code at the gate. Some are on the guest list and show an ID. Some are the band’s own crew and walk in through the staff entrance with a laminated pass. The concert (the protected resource) is the same, but each kind of visitor has a different, appropriate way in.
A grant type is not a feature of the user. It is a choice made by the developer for each application. The same person can sign in through many apps that each use a different grant type.
MMeet the Cast: Roles, Tokens, and Endpoints
Every grant type is a short play with the same four actors. Learn the actors once and every flow becomes easy to read.
The Four Roles
Resource Owner
The person who owns the data, such as an employee whose profile or files are involved. In some flows there is no person at all.
Client
The application asking for tokens: a website, a mobile app, a command-line tool, or a background service. In Okta, every client is registered as an “app integration.”
Authorization Server
The system that checks identity, applies rules, and issues tokens. In this guide, that is Okta.
Resource Server
The API that holds the protected data and accepts access tokens, such as an orders API or a reporting service.
The Three Tokens
An ID token tells the app who signed in. It is meant for the app only, never for calling APIs. An access token is the visitor badge for an API. It lists what the app may do and expires quickly. A refresh token is a longer-lived voucher that can be traded for a new access token without asking the user to sign in again.
Okta issues these tokens as signed JSON Web Tokens, called JWTs. A JWT is a small text package with three parts: a header, a body of facts called claims, and a signature. The signature is like a wax seal. Anyone can read the letter, but nobody can change it without breaking the seal.
The Two Doors on Okta
Almost every flow talks to Okta through two endpoints. The authorize endpoint is the front door where a person is sent to prove who they are. The token endpoint is the back counter where the app trades a proof for tokens. Some grant types skip the front door entirely, and some add a third endpoint, as you will see later.
Scopes: What the Badge Opens
A scope is a short word describing a permission, such as openid, profile, email, or offline_access. The app lists the scopes it wants. Okta decides which ones to actually grant. The special scope openid is what turns an OAuth request into an OIDC request and causes an ID token to be issued. The scope offline_access asks for a refresh token.
| Token | Who reads it | Typical lifetime | Main purpose |
|---|---|---|---|
| ID token | The client app | Short, about an hour | Prove who signed in |
| Access token | The API (resource server) | Short, about an hour by default | Authorize API calls |
| Refresh token | Okta token endpoint only | Long, set by policy | Get new access tokens quietly |
Never send an ID token to an API as if it were an access token, and never read an access token in your client to learn who the user is. Each token has one job. Mixing them is a classic beginner bug that sometimes works in testing and then fails in production.
HHow Okta Organizes Grant Types
In Okta, two settings decide whether a grant type works: what the app is allowed to ask for, and what the authorization server is willing to give.
Application Types
When you create an app integration in Okta, you choose an application type. This choice quietly sets safe defaults for which grant types are available.
Web Application
Server-side apps that can keep a secret. Typically use Authorization Code and Refresh Token, and sometimes Client Credentials.
Single-Page Application
Browser apps built with frameworks like React or Angular. They cannot hide a secret, so they use Authorization Code with PKCE.
Native Application
Phone, tablet, and desktop apps. They use Authorization Code with PKCE, and can also use Refresh Token and Device Authorization.
API Services (Machine to Machine)
Background services with no person involved. They use Client Credentials only.
Public Clients and Confidential Clients
OAuth splits clients into two groups. A confidential client can keep a secret safe, because its code runs on a server you control. A public client cannot, because its code is shipped to a browser or a phone where anyone can inspect it. This single idea explains most of the rules in the rest of this guide. Public clients need extra protection, which is exactly what PKCE provides.
Two Kinds of Authorization Server
Okta offers an Org Authorization Server, built into every Okta account, mainly meant for signing people in to Okta-connected apps and for calling Okta’s own management APIs. It also offers Custom Authorization Servers, where you define your own scopes, claims, and policies to protect your own APIs. Okta creates one named “default” in many accounts to get you started. If you are protecting your company’s APIs, you almost always want a custom authorization server.
Access Policies: The Second Gate
Inside a custom authorization server you create access policies and, inside those, rules. A rule can say “for this app, for these users, allow only these grant types, these scopes, and give access tokens a lifetime of this long.” This is powerful. Even if an app is registered to use a grant type, a rule can still refuse it. When something fails with a message about the grant type being unauthorized, check both the app settings and the policy rule.
flowchart LR
A["Client App"] -->|"1. Request tokens"| B["Okta Authorization Server"]
B --> C{"App allows this grant type?"}
C -->|"No"| X["Error: unauthorized_client"]
C -->|"Yes"| D{"Access policy rule allows it?"}
D -->|"No"| Y["Error: no matching policy"]
D -->|"Yes"| E["Tokens issued"]
E --> F["Resource Server API"]
It is like boarding a flight. Your ticket (the app setting) says you may fly. But the gate agent (the policy rule) still checks that this particular flight, today, allows you on board. Both must say yes.
AAuthorization Code Grant
The workhorse of the web. If an app has a server that can keep a secret and a person who signs in, this is the grant to use.
The Idea in One Sentence
The user signs in at Okta, Okta hands the app a short-lived authorization code through the browser, and the app secretly trades that code for tokens directly with Okta.
Why Two Steps?
The browser is a leaky place. URLs end up in history, logs, and screenshots. So Okta never puts tokens in the browser address bar. It puts only a one-time code there. That code is useless on its own because exchanging it requires the app’s secret, and the exchange happens on a private server-to-server connection. A thief who steals the code from the URL still cannot get tokens.
Picture a coat-check claim ticket. The ticket itself is not your coat. You give the ticket to the attendant, and only then do you receive the coat. If someone sees your ticket, they still need to prove they are allowed to collect the coat. The authorization code is the claim ticket, and the client secret is your proof.
Step by Step
The app redirects the user to Okta
The app sends the browser to the authorize endpoint with its client ID, requested scopes, a redirect address, and a random value called state.
The user signs in
Okta shows its sign-in page, applies multifactor rules, and may ask the user to approve the requested permissions.
Okta redirects back with a code
The browser returns to the app’s redirect address carrying the one-time code and the same state value.
The app checks the state
If the returned value does not match what the app sent, the app stops. This blocks forged requests.
The app exchanges the code at the token endpoint
The server sends the code plus its client credentials directly to Okta. The code lives only about a minute and works once.
Okta returns the tokens
The app receives an ID token, an access token, and optionally a refresh token, then validates them before use.
sequenceDiagram
autonumber
actor U as User
participant B as Browser
participant A as Web App Server
participant O as Okta
participant R as Resource API
U->>B: Click Sign in
B->>A: Request protected page
A->>B: Redirect to Okta authorize endpoint
B->>O: Authorize request with state
O->>U: Show sign in and MFA
U->>O: Authenticate
O->>B: Redirect with code and state
B->>A: Deliver code and state
A->>O: Token request with code and client secret
O->>A: ID token, access token, refresh token
A->>R: API call with access token
R->>A: Protected data
Client Authentication Choices
When the server calls the token endpoint, it must prove it is the real app. Okta supports several ways. A client secret sent in a header or a form is the simplest. A signed client assertion using a secret key is stronger. And private key JWT, where the app signs a short statement with a private key and Okta checks it with the matching public key, is the strongest because no shared secret ever crosses the network.
Production example: a corporate intranet portal
A large retailer runs an employee portal on its own servers. Staff click Sign in, land on the Okta page, finish multifactor checks, and return to the portal. The portal server holds the client secret in a secrets vault and exchanges the code behind the scenes. Employees never see a token, and the browser history never contains one.
Even confidential clients should now use PKCE with this grant. It costs almost nothing and protects against code theft. Newer OAuth guidance treats PKCE as the default for every authorization code flow.
PAuthorization Code with PKCE
The same flow as before, with one clever addition that lets apps without a secret stay safe. This is the default choice for browser apps and mobile apps.
The Problem PKCE Solves
A single-page app or a phone app is a public client. Its code lives on the user’s device, so any “secret” inside it can be pulled out by someone with enough curiosity. Worse, on phones, a malicious app can sometimes register to receive the same redirect as a real app and quietly grab the authorization code on its way back. Without a secret to protect the exchange, the thief could trade the stolen code for tokens.
PKCE, pronounced “pixy” and short for Proof Key for Code Exchange, fixes this by creating a fresh, one-time secret for every single sign-in. The app never stores it. It lives only in memory for a few seconds.
How PKCE Works
Before redirecting, the app invents a long random string called the code verifier. It is typically between 43 and 128 characters. The app then runs it through a one-way scrambler, the SHA-256 hash, to produce the code challenge. Only the challenge is sent to Okta on the way out. Okta remembers it alongside the code it issues.
When the app later trades the code for tokens, it sends the original verifier. Okta scrambles it again and compares. If the results match, the same app that started the flow is the one finishing it. A thief who stole only the code does not know the verifier, and because scrambling is one-way, the challenge seen earlier cannot be reversed to reveal it. Okta supports the S256 method, which is the secure one.
You hand a stranger a sealed envelope and keep a secret handwriting sample at home. Later, when someone comes to collect your parcel, you ask them to write the same sample. Only the real you can do it. The envelope is the challenge. The handwriting sample is the verifier.
sequenceDiagram
autonumber
actor U as User
participant S as SPA or Mobile App
participant O as Okta
participant R as Resource API
S->>S: Create code verifier and code challenge
S->>O: Authorize request with challenge and state
O->>U: Sign in and MFA
U->>O: Authenticate
O->>S: Redirect with code and state
S->>O: Token request with code and original verifier
O->>O: Hash verifier and compare with stored challenge
O->>S: ID token and access token
S->>R: API call with access token
R->>S: Protected data
What Okta Requires
Okta enforces PKCE for single-page and native app types, and encourages it everywhere else. For a browser app you also need to register the app’s address as a trusted origin, because the browser makes a cross-site call to Okta’s token endpoint and Okta must explicitly allow it. Forgetting this step gives blocked-request errors that look scary but are easy to fix.
Redirect addresses are matched exactly. If you registered one address and your app sends a slightly different one, even a trailing slash, Okta refuses the request. This is a deliberate security rule, not a bug.
Production example: sign-in with Google on mobile
Google’s own guidance for mobile and desktop apps is the authorization code flow with PKCE, because the app has no safe place to hide a secret. The same pattern is what an Okta-protected banking app or field-service app on a phone should follow: open the system browser, sign in, come back with a code, and prove it with the verifier.
Mobile apps should open the sign-in page in the phone’s secure system browser, not in an embedded web view inside the app. Embedded views let the app watch what the user types, which defeats the purpose of single sign-on and breaks trust.
CClient Credentials Grant
No person, no browser, no sign-in page. This grant is for software talking to software.
When There Is No User
Some work happens with nobody watching: a nightly report generator, a billing microservice calling an invoice API, or a script syncing records between systems. These programs are not acting on behalf of a person. They act on behalf of themselves. The Client Credentials grant gives them tokens based only on proving their own identity.
How It Works
The service sends a single request to the token endpoint with its credentials and the scopes it needs. Okta checks the app, checks the policy, and returns an access token. That is the whole flow. There is no ID token, because there is no user to identify, and normally no refresh token, because the service can simply ask again.
sequenceDiagram
autonumber
participant J as Backend Service
participant O as Okta Token Endpoint
participant R as Resource API
J->>O: Token request with client credentials and scopes
O->>O: Check app settings and access policy rule
O->>J: Access token only
J->>R: API call with access token
R->>R: Validate signature, issuer, audience, scopes
R->>J: Protected data
Proving Who the Service Is
A service can use a client secret, which is easy but means a shared password lives somewhere. Better is private key JWT: the service holds a private key, signs a short-lived statement saying “I am this client,” and Okta verifies it with the public key you uploaded. If Okta’s database were ever leaked, there would be no secret in it to steal.
Scopes Define Power
For your own APIs, you define custom scopes on a custom authorization server, such as a read-only scope for invoices and a separate write scope. Give each service only the smallest set it needs. When a service calls Okta’s own management APIs, Okta uses its own scopes like those for reading users, and requires the stronger private key method. Okta also lets you add proof-of-possession tokens through DPoP, which ties a token to a key held by the caller so a stolen token alone cannot be reused.
This is the staff entrance. A delivery company with a signed contract does not queue with the public. Its driver shows a company badge, gets a badge good for the loading dock only, and never enters the main lobby. The contract is the registration, the company badge is the key, and the dock-only pass is the scoped access token.
Strengths
- Very simple and fast, with a single request
- No browser redirects to break
- Easy to scope per service and to rotate keys
- Perfect for automation and scheduled jobs
Cautions
- The service has real power, so a leaked credential is serious
- Never use it from a browser or phone app
- No user identity in the token, so auditing “who” needs extra design
- Long-lived secrets tend to be forgotten and never rotated
Production example: a company service calling an internal API
Picture the way a large ride-sharing or e-commerce company wires its internal services: a pricing service asks a catalog service for product data many thousands of times a minute. Each caller holds its own identity, requests a short-lived token with a narrow scope, caches it until shortly before expiry, and reuses it. This is the standard shape of machine-to-machine access with Okta, and it is why services should cache tokens rather than request a new one for every call.
RRefresh Token Grant
Short-lived access tokens are safer, but nobody wants to sign in every hour. Refresh tokens solve that tension.
Why Access Tokens Are Short
An access token works like cash. Whoever holds it can spend it, and the API cannot tell a thief from the owner. So we keep its life short, often about an hour by default in Okta, to limit the damage if one leaks. But a short life creates an annoying problem for users who are working all day.
The Refresh Token Solution
A refresh token is a special long-lived token that the app keeps safely and later sends to the token endpoint, together with the grant type name “refresh_token,” to get a brand new access token. The user notices nothing. To receive one in Okta, the app must request the offline_access scope, and the app and policy must allow the Refresh Token grant.
Refresh Token Rotation
A refresh token that never changes is a risk, because if it leaks, an attacker can quietly use it for a very long time. Okta supports rotation: every time you use a refresh token, Okta hands you a new one and retires the old. If an old one is ever used again, that is a strong sign of theft, and Okta treats it as an attack by revoking the whole chain of tokens that came from it. Okta also offers a small grace period, a matter of seconds, so that a slow network or a retried request does not accidentally trigger the alarm.
For browser apps, rotation is the expected setup, since browsers are the hardest places to protect long-lived credentials.
Initial sign-in
The app signs the user in and receives an access token plus a refresh token.
Access token expires
An API call comes back unauthorized, or the app notices the expiry time first.
Silent refresh
The app sends the refresh token to Okta and receives a new access token and a new refresh token.
Old token retired
The previous refresh token is no longer valid. Reuse of it triggers revocation of the chain.
Session ends
When the refresh token reaches its policy-defined limit or the user is signed out, the person must sign in again.
In a custom authorization server, the access policy rule controls how long access tokens and refresh tokens live, and whether refresh tokens expire after a fixed time or after a period of inactivity. Pick shorter values for sensitive data and longer ones for low-risk convenience apps.
Production example: a streaming app on your phone
Think about apps like Netflix or Spotify on a phone. You sign in once and stay signed in for weeks. Behind the scenes, apps of this kind use long-lived credentials to quietly obtain fresh short-lived tokens. In an Okta-based product, the refresh token grant is how that “stay signed in” experience is delivered without ever storing a password.
DDevice Authorization Grant
For devices where typing a password is painful or impossible, such as smart TVs, game consoles, and command-line tools.
The Typing Problem
Have you ever tried to enter a long email and password using a TV remote? It is slow and error-prone. Some devices, like a small display in a factory or a terminal on a server, have no browser at all. The Device Authorization grant lets such a device ask the user to finish signing in on a different device that is easier to use, like a phone or laptop.
How It Works
The device first calls Okta’s device authorize endpoint. Okta responds with a device code meant for the device itself, a short user code meant for the human to type, and a verification address. The device shows the user code and address on screen. The user opens that address on their phone, signs in with all the usual security, and enters the code. Meanwhile the device politely asks Okta every few seconds, “Are we done yet?” This is called polling. As soon as the user approves, the next poll returns tokens.
sequenceDiagram
autonumber
actor U as User
participant D as TV or CLI Device
participant P as Phone or Laptop Browser
participant O as Okta
D->>O: Device authorize request with scopes
O->>D: Device code, user code, verification address
D->>U: Show user code and address
U->>P: Open the address
P->>O: Sign in and enter user code
O->>P: Approve device
loop Every few seconds
D->>O: Poll token endpoint with device code
O->>D: Authorization pending
end
D->>O: Poll token endpoint with device code
O->>D: Access token and optional ID token
Polling Rules and Errors
Okta tells the device how long to wait between polls, commonly about five seconds. If the device asks too fast, Okta answers with a slow-down message and the device must back off. If the user has not finished, the answer is “authorization pending.” If the user refuses, the answer is access denied. If too much time passes, usually about ten minutes, the codes expire and the process starts over.
It is like a restaurant pager. You do not stand at the counter watching the kitchen. You take a pager, go sit down, and when your order is ready the pager buzzes. The device is the pager, the phone is you at the counter proving who you are, and polling is the pager checking for news.
Production example: GitHub CLI and YouTube on TV
When you run the GitHub command-line tool’s login command, it shows a short code and asks you to open a page in your browser. When you activate YouTube on a smart TV, the screen shows a code and tells you to visit an activation page on your phone. Both are exactly this grant. Okta customers use the same pattern for internal command-line tools, kiosks, and TV or set-top box apps.
Attackers can try to trick a person into entering a code that the attacker’s device generated. Teach users to enter a code only when they themselves just started a sign-in on a device in front of them, and show clear text on the approval page saying which app is requesting access.
IImplicit and Hybrid Flows: The Legacy Path
You will still see these in older apps and old tutorials. Understand them so you can recognize and retire them.
What Implicit Did
The Implicit grant was invented when browser apps could not make cross-site calls. To work around that, it skipped the code step and returned tokens straight in the browser’s address bar fragment, right after sign-in. It was quick and needed no server. That was the reason it became popular for early single-page apps.
Why It Fell Out of Favor
Putting tokens in the address bar means they can end up in browser history, be read by scripts on the page, or leak through other browser features. There is no way to know whether the app that finished the flow is the app that started it. And there is no safe way to get refresh tokens. Security guidance, including the newer OAuth 2.1 direction, removes it. Modern browsers can now make the cross-site call that PKCE needs, so the original reason for Implicit is gone.
Hybrid Flow
The Hybrid flow mixes the two: Okta returns an ID token, or sometimes other values, directly in the browser while also returning a code to exchange on the server. It exists for special cases, such as a server-side web app that wants to verify the user quickly before the code exchange. In Okta, both Implicit and Hybrid are used only when you deliberately enable the Implicit option on the app, and they are best treated as a compatibility feature.
Context
A team inherits a single-page app that gets tokens through Implicit because an old tutorial said so.
Problem
Tokens appear in the browser address bar, cannot be bound to the original request, and there is no safe refresh path.
Better decision
Migrate to Authorization Code with PKCE. Register the redirect addresses and trusted origins, switch the app type settings, add refresh token rotation, and then turn off Implicit on the app so it cannot be used again.
RResource Owner Password Grant
The grant that asks an app to collect a username and password itself. Okta still supports it, but it is a last resort.
What It Does
In the Resource Owner Password grant, the app shows its own login form, takes the person’s username and password, and posts them straight to the Okta token endpoint. Okta checks them and returns tokens. There is no redirect, no Okta sign-in page, and no browser dance.
Why It Is Risky
The whole point of OAuth was to stop apps from seeing passwords. This grant brings that problem right back. The app can log, steal, or mishandle the password. It also cannot easily support modern sign-in steps such as push approval, security keys, or risk checks, because those need a real sign-in page. In Okta, if the rules for the app require more than a password, this grant simply fails. It is also disabled by default for good reason.
When You Might Still See It
Teams sometimes use it for a short time while migrating an old system that already owns the login form, or for quick testing. If you must use it, treat it as temporary, limit it to a first-party app you fully control, and write down a plan to replace it with Authorization Code with PKCE.
Context
A mobile team wants a custom-looking login screen and decides to send the password directly to Okta.
Problem
The app handles raw passwords, cannot use strong factors, and trains users to type credentials into any screen that looks right.
Better decision
Use Authorization Code with PKCE through the system browser. If a fully branded experience is truly needed, evaluate Okta’s embedded sign-in options designed for that purpose rather than a raw password grant.
SSpecialized Grants in Okta
Beyond the common flows, Okta supports a handful of specialist grants. You will not need them every day, but you should know they exist.
Token Exchange
A service trades one token for another, for example a user’s token for a new one aimed at a different API. It helps when a chain of services needs to carry the original user’s identity forward safely.
SAML 2.0 Assertion
An app that already holds a SAML sign-in proof can trade it for OAuth tokens. This bridges older SAML-based systems and newer API-based ones.
Interaction Code
Used by Okta’s embedded sign-in SDKs, where the app drives the sign-in screens itself while Okta still makes every security decision. It ends with a normal token response.
Direct Authentication Grants
A family of Okta-specific grants for native apps that collect factors such as one-time passcodes or out-of-band approvals directly, without a browser, under strict policy control.
These grants are powerful and narrow. Reach for them only when a clear requirement demands them, and read the current Okta documentation for your exact edition before building, because available options can differ by product version and licensing.
CChoosing the Right Grant Type
You now know the options. Here is a simple way to pick without second-guessing yourself.
Ask Three Questions
First: is a person involved? If not, use Client Credentials. Second: if a person is involved, does the device have a browser and a keyboard? If not, use Device Authorization. Third: if it does, can the app keep a secret? A server-side web app can, but should still use PKCE. A browser app or phone app cannot, so it must use Authorization Code with PKCE. Then add Refresh Token if users should stay signed in.
flowchart TD
S["Start: what is the client?"] --> Q1{"Is a person signing in?"}
Q1 -->|"No"| CC["Client Credentials"]
Q1 -->|"Yes"| Q2{"Does the device have a browser and easy typing?"}
Q2 -->|"No"| DA["Device Authorization"]
Q2 -->|"Yes"| Q3{"Can the app keep a secret on a server?"}
Q3 -->|"Yes"| AC["Authorization Code plus PKCE"]
Q3 -->|"No"| AP["Authorization Code with PKCE"]
AC --> RT{"Should users stay signed in?"}
AP --> RT
RT -->|"Yes"| RF["Add Refresh Token with rotation"]
RT -->|"No"| DONE["Done"]
| Grant type | Best for | User involved? | Needs secret? | Recommendation |
|---|---|---|---|---|
| Authorization Code with PKCE | SPAs, mobile, desktop, and web apps | Yes | No for public clients | Default choice |
| Authorization Code | Server-side web apps | Yes | Yes | Good, add PKCE |
| Client Credentials | Services and automation | No | Yes or key | Good for machines only |
| Refresh Token | Staying signed in | Yes | Depends | Good with rotation |
| Device Authorization | TVs, consoles, CLIs | Yes, on another device | No | Good for limited devices |
| Implicit | Old browser apps | Yes | No | Avoid, migrate away |
| Resource Owner Password | Legacy migration only | Yes | Depends | Avoid |
TToken Lifecycle and Validation
Getting a token is only half the story. What happens next decides whether your system is actually secure.
The Life of a Token
A token is born when Okta signs it, used when a client sends it to an API, checked by the API, and then dies by expiring or being revoked. Every step matters. Many real incidents come not from weak sign-in, but from an API that accepts a token it never properly checked.
What an API Must Check
An API should confirm that the signature is valid using Okta’s published public keys, which are found at a keys address called the JWKS endpoint, short for JSON Web Key Set. It must also confirm the issuer, meaning the token came from the right Okta authorization server, the audience, meaning the token was meant for this API, and the expiry time. Finally it must confirm the required scopes are present for the action being requested. Skipping the audience check is a surprisingly common mistake.
Verify the signature
Use the public key matching the key ID in the token header. Cache keys, but refresh them when Okta rotates signing keys.
Check issuer and audience
Reject tokens from other authorization servers or meant for other APIs.
Check time claims
Reject expired tokens and tokens that are not yet valid, allowing only a tiny clock tolerance.
Check scopes and claims
Allow only the actions the token’s scopes permit, and apply your own business rules for roles and groups.
Local Validation or Introspection?
Checking the signature locally is fast and needs no call to Okta, which is perfect for high-traffic APIs. The downside is that a token stays acceptable until it expires, even if it was revoked. Introspection means asking Okta, “is this token still active right now?” It gives real-time answers but adds a network call. Many teams validate locally for most calls and use introspection for the most sensitive actions.
Revocation
Okta lets an app revoke its tokens when a user signs out, and lets administrators end sessions and revoke tokens when an account is compromised. Remember that an already-issued, self-contained access token may still be accepted by APIs that only validate locally until it expires. That is one more reason to keep lifetimes short.
Think of a concert wristband. The guard at each door checks the band’s color, date, and hologram without calling the box office. That is local validation. For the VIP lounge, the guard radios the box office to confirm the band was not cancelled. That is introspection.
SSecurity Essentials
A short list of habits that prevent most of the damage in real deployments.
Register exact redirect addresses
Never use wildcards. A loose redirect rule lets an attacker steer a code or token to a page they control.
Use state and nonce
The state value blocks forged callbacks. The nonce value ties an ID token to one specific sign-in so a stolen token cannot be replayed.
Use PKCE everywhere
It protects stolen codes for both public and confidential clients at almost no cost.
Prefer private key authentication
For services, signed assertions beat shared secrets because no reusable password sits in a database.
Request the minimum
Narrow scopes mean a stolen token can do less harm. Review them regularly.
Store tokens carefully
Keep secrets in a vault on servers. In browsers and phones, use the safest storage the platform provides, and keep tokens out of logs and URLs.
Common Attacks and Their Defenses
| Attack | What it tries | Defense |
|---|---|---|
| Code interception | Steal an authorization code and exchange it | PKCE, exact redirects, short code lifetime |
| Cross-site request forgery | Trick a user into finishing the attacker’s sign-in | Random state value checked on return |
| Token replay | Reuse a stolen token elsewhere | Short lifetimes, audience checks, DPoP |
| Refresh token theft | Keep minting new access tokens silently | Rotation with reuse detection |
| Secret leakage | Find a client secret in code or logs | Vaults, rotation, private key JWT |
| Open redirect | Send tokens to a hostile page | Strict redirect registration |
Never put a client secret in a browser app, a phone app, or any code that you ship to users. Anything shipped to a device can be extracted. If your design needs a secret there, the design needs to change.
SScopes, Claims, and Shaping Your Tokens
Grant types decide how a token is obtained. Scopes and claims decide what is inside it. Together they control what a token can actually do.
Scopes: Asking for Permission
A scope is a request, and Okta decides whether to grant it. On a custom authorization server you create scopes that match your business, such as one for reading orders and another for creating refunds. Names that read clearly are easier to review during a security audit. A scope can be marked as a default scope, which means it is included even when the app does not ask for it by name, and it can be set to require user consent, which shows the person a screen listing what the app wants before anything is shared.
Consent matters most for third-party apps that your company does not own. For your own internal apps, teams usually skip the consent screen, since employees already agreed to use the company’s tools. Okta lets you choose this per app, so a partner’s app can show consent while your own portal stays quiet.
Claims: Facts Inside the Token
A claim is one fact stored in a token, such as the issuer, the audience, the expiry time, the subject (the unique identifier of the user or service), and any extra facts you add. On a custom authorization server you can add claims that carry a user’s groups, department, or a customer number. Okta fills these in when the token is created, using simple expressions that read from the user’s profile.
Be careful with what you place inside tokens. Tokens are readable by anyone who holds them, since the signature protects against changes but not against reading. Do not place sensitive personal data in a token, and remember that large tokens slow down every request, because they travel on each API call. A good rule is to put identifiers and roles in the token and let the API look up the rest from its own database.
Claims can be placed in the ID token, the access token, or both. Put identity facts for the client into the ID token, and put authorization facts for the API into the access token. This keeps each token focused on its single job.
Which Grant Types Can Carry Which Scopes?
Not every scope makes sense with every grant type. The openid, profile, and email scopes describe a person, so they belong with flows that involve a user. They do nothing useful with Client Credentials, because no person signs in. The offline_access scope asks for a refresh token and belongs with user flows that should last. Custom scopes for your own API can be used with both user flows and machine flows, and the access policy rule decides which combinations are allowed for each app.
| Scope | Purpose | Works with user flows | Works with Client Credentials |
|---|---|---|---|
| openid | Turns on OIDC and returns an ID token | Yes | No |
| profile | Name and basic profile facts | Yes | No |
| Email address and verification status | Yes | No | |
| offline_access | Asks for a refresh token | Yes | No |
| Custom API scope | Defines what an API allows | Yes | Yes |
A scope is the list of rooms a hotel key card can open, and claims are the words printed on the card, like the guest’s name and checkout date. The door lock does not call the front desk each time. It reads the card and decides on the spot. That is why what you print on the card, and what rooms you allow, must be chosen carefully.
IInside Okta: What Happens to a Request
You do not have to know how Okta is built to use it well, but a mental picture of the steps makes errors far easier to understand.
The Front Door: The Authorize Endpoint
When a browser arrives at the authorize endpoint, Okta first checks that the request makes sense. It looks up the client ID and confirms the app exists and is active. It checks that the redirect address exactly matches one on the registered list. It checks that the requested response type and scopes are allowed. If any of these checks fail, Okta shows an error page rather than redirecting, because redirecting an unverified request could send a person to a hostile site.
Next Okta looks for an existing session, a small record, tied to a cookie in the browser, that says this person has already signed in. If a valid session exists and policy allows it, the person skips the sign-in page entirely. This is what makes single sign-on feel magical: sign in once in the morning and open ten apps without typing a password. Apps can also ask Okta to force a fresh sign-in or to avoid showing any page at all, which is how apps quietly check whether a session still exists.
Policy Evaluation
Before a person is allowed through, Okta evaluates sign-in policies. These consider who the user is, which groups they belong to, where the request comes from, what device they use, and how risky the situation looks. The result may be to allow, to ask for another factor such as a push approval or a security key, or to deny. Only after these pass does Okta create the authorization code.
The Code Is Stored, Not Trusted
The authorization code is a random value that points to a record inside Okta. The record holds who signed in, which app asked, which scopes were approved, the redirect address, and the PKCE challenge if one was sent. The code lives for only a minute or so and can be used once. When the app arrives at the token endpoint, Okta looks the record up, compares every detail, and then deletes it.
The Back Counter: The Token Endpoint
The token endpoint does a different job depending on the grant type. For Authorization Code, it verifies the code and the PKCE verifier. For Client Credentials, it verifies the client’s key or secret and then evaluates the access policy. For Refresh Token, it verifies the token and applies rotation. For Device Authorization, it checks whether the person has approved the device yet. In every case, Okta then builds the tokens, fills in claims, signs them with a private key, and returns them.
Signing Keys
Okta signs tokens with private keys that never leave Okta. It publishes the matching public keys at a well-known address so that anyone can verify the signature. Okta rotates these keys on a regular schedule. Because tokens carry the identifier of the key that signed them, an API can pick the right public key and keep working through a rotation, provided it re-fetches the key list when it sees an unfamiliar key identifier instead of caching the list forever.
flowchart TD
A["Request arrives at Okta"] --> B["Validate client and redirect address"]
B --> C{"Existing session?"}
C -->|"Yes"| D["Evaluate policies"]
C -->|"No"| E["Show sign in page"]
E --> D
D --> F{"Extra factor needed?"}
F -->|"Yes"| G["Ask for factor"]
G --> H["Create one time code record"]
F -->|"No"| H
H --> I["Redirect to app with code"]
I --> J["App calls token endpoint"]
J --> K["Verify code, client, and PKCE"]
K --> L["Build and sign tokens"]
L --> M["Return tokens"]
Think of an airport. The front door is security and passport control, where officials check your identity and your ticket. The code is a boarding pass printed for one flight only. The token counter is the gate, where the boarding pass is scanned, matched against the flight list, and exchanged for a seat. Each stage has its own checks, and failing any of them stops you from boarding.
TThe Full Session: From Sign-In to Sign-Out
Real users do not run one flow and stop. They sign in, work for hours, lose their network, switch tabs, and finally leave. Here is how the pieces fit together over a whole day.
Morning: The First Sign-In
A user opens a single-page app. The app sees no tokens and starts Authorization Code with PKCE. Okta shows its sign-in page, asks for a second factor, and returns a code. The app exchanges it and receives an ID token, an access token, and a refresh token. The app keeps the access token in memory, uses the ID token to display the user’s name, and stores the refresh token in the safest place the platform allows.
Midday: Quiet Renewals
Every time the access token is close to expiring, the app uses the refresh token. Okta issues a new access token and, with rotation, a new refresh token. The user keeps working and notices nothing. If the user changes jobs and loses access to a group, the next policy evaluation can deny the refresh, and the app is asked to sign in again.
Afternoon: Trouble
If the network drops during a refresh, the app may retry with the same refresh token. This is exactly why Okta offers a short grace period for rotation. The retry succeeds instead of being mistaken for theft. If the retry comes long after the grace period and the old token has already been replaced, Okta treats it as reuse and revokes the chain, and the person must sign in again.
Evening: Sign-Out
When the user clicks sign out, a well-built app does three things. It removes tokens from its own storage. It asks Okta to revoke the refresh token, so it can never be used again. And it can redirect the browser to Okta’s logout endpoint so that the Okta session also ends, which matters on shared computers. Without the last step, the next person at the same browser may find themselves signed in silently.
sequenceDiagram
autonumber
actor U as User
participant A as Single Page App
participant O as Okta
participant R as Resource API
U->>A: Open the app
A->>O: Authorization Code with PKCE
O->>A: ID token, access token, refresh token
A->>R: Call API with access token
R->>A: Data
Note over A,O: One hour later the access token expires
A->>O: Refresh token request
O->>A: New access token and new refresh token
A->>R: Call API with new access token
R->>A: Data
U->>A: Click sign out
A->>O: Revoke refresh token
A->>O: End Okta session
O->>A: Redirect to signed out page
There are really two separate sessions: the app’s own session and the Okta session. Signing out of an app does not automatically sign the person out of Okta, and the other way around. Decide deliberately which behavior your product needs, and test both.
SSetting It Up: The Decisions, Not the Clicks
Menus and screens change from release to release, but the decisions you must make stay the same. Here they are in order.
Choose the authorization server
Use a custom authorization server for your own APIs. Decide the audience value, which is the name your APIs will check for in every token.
Define your scopes
List what your API can do, and create one scope per meaningful action group. Keep names clear and small in number.
Register the app
Pick the application type that matches your client: web, single-page, native, or API services. This sets safe defaults for grant types and client authentication.
Set redirects and origins
Add exact sign-in redirect addresses, sign-out redirect addresses, and trusted origins for browser apps. Keep test and production separate.
Choose how the app proves itself
Pick a secret, a key, or no secret with PKCE based on whether the client is confidential or public.
Create an access policy and rule
Assign the app, then allow only the grant types, scopes, and token lifetimes it needs. Remember that this second gate can block a request even when the app itself allows it.
Assign users or groups
An app that no one is assigned to will refuse every sign-in. Assign groups instead of individuals so that onboarding and offboarding stay automatic.
Test and read the log
Run one successful flow and one deliberate failure, then read both System Log entries so you know what each looks like before production traffic arrives.
Use separate Okta apps, and ideally separate Okta accounts, for development, testing, and production. Copying a production client secret into a laptop test is how many leaks begin.
MMigrating Away from Legacy Grants
Plenty of teams inherit apps that use Implicit or Resource Owner Password. Fixing them is a project, not a panic. Here is a calm way to do it.
Step 1: Find Every Use
Start with the Okta System Log and the app list. Look for apps that have legacy grant types enabled, and for token requests that use them. Many apps have these enabled simply because they were switched on during an early experiment and never switched off. Those are the easiest wins.
Step 2: Move One App at a Time
For a single-page app using Implicit, switch to Authorization Code with PKCE in the app’s code, using a current, well-maintained Okta library rather than hand-built calls. Add the trusted origin, update the redirect address, and add the refresh token with rotation. Test in a non-production Okta account first.
For an app using the Resource Owner Password grant, replace the custom login form with a redirect to the system browser and Okta’s sign-in page. If the product team needs a branded look, Okta’s customizable sign-in page and embedded SDK options are meant for exactly that need.
Step 3: Roll Out Carefully
Ship the new version and keep the old grant enabled for a short window, so users on older app versions are not locked out. Track the number of requests that still use the old grant in the System Log. When the number reaches zero, or the old app version is retired, disable the legacy grant on the app, and optionally in the policy rules as well.
Step 4: Lock the Door
Once everyone has moved, remove the legacy grants from the app settings and from the access policy rules. Write down the decision, so that the next team does not turn them back on to solve a quick problem.
A simple scorecard for the migration
Track four numbers each week: how many apps still allow Implicit, how many still allow Resource Owner Password, how many token requests used each in the past seven days, and how many apps now run with PKCE and rotation. Sharing this small scorecard with leaders turns a vague security cleanup into a visible, finishable project.
TTrade-offs and Design Patterns
Every grant type buys you something and costs you something. Good architects know both sides.
Advantages and Disadvantages of the OAuth and OIDC Model in Okta
Advantages
- Apps never handle passwords in the recommended flows
- One central place for sign-in rules, multifactor checks, and audit
- Tokens are short-lived and scoped, which limits damage from leaks
- Standards-based, so many languages, libraries, and tools work out of the box
- Different grant types fit different client types cleanly
- Policies let you tighten or relax rules per app without code changes
Disadvantages
- Many moving parts: apps, servers, policies, scopes, and trusted origins
- Misconfiguration errors are common and messages can be cryptic
- Self-contained tokens cannot be recalled instantly once issued
- Extra network hops add latency during sign-in and refresh
- Teams must keep up with standards guidance that keeps evolving
Trade-offs You Will Actually Face
Short token lifetime versus user convenience. A five-minute token is very safe but forces frequent refreshes. A one-day token is smooth but risky. Most teams choose around an hour for access tokens and rely on rotating refresh tokens for convenience.
Local validation versus introspection. Local validation scales beautifully, while introspection gives exact, current answers. Choose per API based on how damaging a wrongly accepted token could be.
Shared secret versus private key. Secrets are quick to set up. Keys take a little longer but remove an entire class of leak risk. For anything important, the extra effort pays off.
One authorization server versus several. A single server is simpler. Several servers let you separate audiences, such as customers and employees, with different claims and policies. Separation improves isolation but adds administration.
Patterns That Work
Backend for Frontend
A thin server sits beside a browser app, runs the Authorization Code flow, and keeps tokens away from the browser. The browser only holds a protected session cookie.
API Gateway Validation
A gateway checks signature, issuer, audience, and scopes before any request reaches backend services, so every service benefits from one consistent check.
Token Caching for Services
A service requests one Client Credentials token and reuses it until just before expiry, instead of asking Okta for a token on every call.
Separate Apps Per Purpose
Register one Okta app per client and per environment, so you can rotate keys, change policy, and read logs without affecting anything else.
Anti-Patterns to Retire
Context
A company creates one Okta app and shares its client ID and secret across a dozen services to save time.
Problem
A leak anywhere exposes everything. Logs cannot show which service did what. Rotating the secret means a risky coordinated change across all teams.
Better decision
Create one machine-to-machine app per service with its own key and narrow scopes. Rotation and investigation both become easy.
Context
An API accepts any validly signed token from the company’s Okta account without checking who it was meant for.
Problem
A token issued for a low-risk app can be replayed against a high-risk API, since both were signed by the same server.
Better decision
Always check the audience and required scopes, and use separate audiences for separate APIs.
MMonitoring, Logging, and Troubleshooting
When sign-in breaks at 2 AM, good logs are the difference between a five-minute fix and a long night.
The Okta System Log
Okta records what happens in a searchable System Log. It includes sign-in attempts, token grants, token revocations, policy evaluations, and failures, each with a result, a time, the app, the user when there is one, and often a clear reason. When a token request fails, this is the first place to look, because it often says which policy or setting caused the refusal.
For long-term storage and alerting, Okta can stream these events to outside systems, including popular cloud and security tools. Many AWS-based teams send them to an event bus and then to a security analytics system, so that unusual patterns trigger alerts automatically.
What to Watch
Track how many token requests succeed and fail for each app. Watch for repeated failures from one client, which may signal a broken deployment or an attack. Pay special attention to refresh token reuse events and to new apps or policies appearing unexpectedly. Okta also applies rate limits to its endpoints, and answers excess calls with an error that includes headers showing when you can try again. A service that requests a fresh token for every call will hit these limits quickly, which is another strong reason to cache tokens.
Common Errors and What They Mean
| Error message | Plain-English meaning | Usual fix |
|---|---|---|
| invalid_client | Okta does not accept the app’s credentials | Check client ID, secret, key, and which authentication method the app uses |
| invalid_grant | The code or refresh token is wrong, used already, or expired | Exchange the code once and quickly. Check PKCE verifier and redirect address |
| invalid_scope | A requested scope does not exist or is not allowed | Check scope names and the policy rule |
| unauthorized_client | The app is not allowed to use this grant type | Enable the grant type on the app and in the policy rule |
| unsupported_grant_type | The server does not support that grant for this request | Check the endpoint and the authorization server in use |
| access_denied | The user or a policy refused | Check assignments, policy, and user choice |
| Redirect address mismatch | The sent address is not on the registered list | Register the exact address, including slashes and ports |
Check the app type and enabled grant types first. Then check the redirect addresses and trusted origins. Then check the access policy rule. Then read the System Log entry for the failed request. This order solves most problems in minutes.
BBest Practices and Common Mistakes
A checklist you can pin next to your monitor.
Do This
- Use Authorization Code with PKCE for every user-facing app, and add Refresh Token with rotation for sessions that should last.
- Use a custom authorization server for your own APIs, with clear audiences and scopes.
- Give every service its own Okta app and its own key.
- Prefer private key authentication for services, and rotate keys on a schedule.
- Validate signature, issuer, audience, expiry, and scopes on every API call.
- Keep token lifetimes as short as the user experience reasonably allows.
- Turn off every grant type an app does not need.
- Stream logs to your monitoring system and alert on unusual behavior.
Common Mistakes
Using the ID token as an API key
ID tokens prove sign-in to the client. APIs should only accept access tokens made for them.
Secrets in front-end code
Anything shipped to a browser or phone is public. Use PKCE instead of a secret.
Wildcard redirects
Convenient in testing, dangerous in production. Register every exact address.
Requesting tokens on every call
This wastes time and triggers rate limits. Cache and reuse until near expiry.
Using the default server for everything
Mixing unrelated APIs and audiences under one server weakens isolation and makes policy messy.
Ignoring token expiry
Apps that never handle expiry produce random failures an hour after sign-in. Always plan for refresh or re-sign-in.
RReal-World Architectures
Three typical systems that combine several grant types, described in everyday terms.
1. A customer portal with a web front end and APIs
Customers sign in through a single-page app using Authorization Code with PKCE. The app receives an access token for the company’s orders API, and a rotating refresh token so customers stay signed in for days. The API gateway validates every token’s signature, issuer, audience, and scopes. A separate reporting service runs nightly using Client Credentials with its own key and read-only scopes.
2. An employee mobile app on managed phones
The app uses Authorization Code with PKCE in the system browser, so Okta’s stronger sign-in rules and security keys apply. Refresh tokens keep staff signed in through the working day. When a phone is lost, an administrator revokes tokens and ends the session, and the app is locked out within the short remaining life of the access token.
3. A set-top box and a command-line tool for support engineers
A set-top box app and an internal diagnostics command-line tool both use Device Authorization. The user sees a short code, finishes sign-in on a phone with multifactor checks, and the device receives scoped tokens. No passwords are typed on the device itself.
flowchart LR
U["Customer Browser SPA"] -->|"Auth Code with PKCE"| O["Okta Custom Authorization Server"]
M["Employee Mobile App"] -->|"Auth Code with PKCE and Refresh"| O
T["CLI or Set-top Device"] -->|"Device Authorization"| O
J["Nightly Reporting Service"] -->|"Client Credentials"| O
O -->|"Access tokens"| G["API Gateway"]
G -->|"Validated requests"| S1["Orders Service"]
G -->|"Validated requests"| S2["Reporting Service"]
O -->|"System Log events"| L["Monitoring and Alerts"]
UUntangling Similar-Sounding Terms
Identity has a lot of overlapping vocabulary. Clearing up these pairs will save you hours of confused searching.
Authentication Versus Authorization
Authentication answers “who are you?” and authorization answers “what are you allowed to do?” OIDC mainly handles authentication through the ID token. OAuth 2.0 mainly handles authorization through the access token. A common beginner mistake is to treat an access token as proof of identity, or to treat the ID token as permission to call an API. Keep the two questions separate in your head and in your code.
Grant Type, Flow, and Response Type
People use these words loosely, and that is fine in conversation, but the exact meanings help when reading documentation. A grant type is the name the token endpoint understands, such as the authorization code, client credentials, or refresh token grant. A flow is the whole journey, including browser redirects and steps before the token endpoint. A response type is a value sent to the authorize endpoint that says what the app wants back first, such as a code. When someone says “the Authorization Code flow,” they mean the full journey. When Okta shows a checkbox for “Authorization Code,” it is the grant type.
OIDC Versus SAML
SAML is an older sign-in standard that passes signed XML documents through the browser. It is common in older enterprise software and is still widely used for employee sign-in to business apps. OIDC is newer, lighter, and uses JSON tokens, which makes it a much better match for mobile apps, single-page apps, and APIs. Okta supports both. If you are building something new and the app supports it, OIDC is usually the simpler path. If a vendor’s product only supports SAML, use SAML for that app and do not worry about mixing them in the same company.
Org Authorization Server Versus Custom Authorization Server
The Org authorization server is the built-in one, used mostly for signing people in to apps and for calling Okta’s own management APIs. A custom authorization server is one you create to protect your own APIs. It supports your own scopes, claims, audiences, and detailed access policies. Tokens from the two servers have different issuers, so an API must be configured to trust the right one. Mixing them up is one of the most common causes of “invalid token” errors.
Public Client Versus Confidential Client
This pair decides most of your design. A confidential client runs where code cannot be inspected by users, such as a server, and can hold a secret or a private key. A public client runs where users can inspect everything, such as a browser or phone, and cannot keep any secret. Public clients rely on PKCE. Confidential clients use secrets or keys and should add PKCE as well.
| Term | One-line meaning | Where you meet it |
|---|---|---|
| Authentication | Proving who someone is | ID token, sign-in page |
| Authorization | Deciding what someone may do | Access token, scopes |
| Grant type | The recipe used to get tokens | Token endpoint, app settings |
| Scope | A named permission | Request, policy rule |
| Claim | A fact inside a token | JWT body |
| Audience | Who the token is meant for | API validation |
| Issuer | Who created the token | API validation |
| Trusted origin | A web address allowed to call Okta from a browser | Okta security settings |
Identity words start with “I”: ID token, identity, issuer. Permission words start with “A”: access token, authorization, audience. It is not perfect, but it helps when you are reading a token under pressure.
FFrequently Asked Questions
SSummary and Key Takeaways
If you remember only a few things from this guide, remember these.
Key Takeaways
- A grant type is a recipe for getting tokens. Different clients need different recipes, and Okta checks both the app settings and the policy rule before issuing anything.
- Authorization Code with PKCE is the default for web, single-page, and mobile apps. Add Refresh Token with rotation for long sessions.
- Client Credentials is for machines only. Give each service its own app, narrow scopes, a private key, and cached tokens.
- Device Authorization fits TVs and command-line tools by moving sign-in to a second device while the first one polls.
- Implicit and Resource Owner Password are legacy. Plan their removal and disable them on apps that no longer need them.
- APIs must validate every token by checking signature, issuer, audience, expiry, and scopes, and should never accept ID tokens.
- Watch the System Log. Alert on failure spikes and refresh token reuse, and stream events into your monitoring tools.