Okta’s OAuth2 Authorization Server doesn’t just grant tokens; it’s a programmable policy engine that dynamically issues tokens based on the context of a request.
Let’s see it in action. Imagine a user trying to access a protected resource.
sequenceDiagram
participant User
participant ClientApp as Client Application
participant OktaAuthServer as Okta Auth Server
participant ResourceServer as Resource Server
User->>ClientApp: Request access to resource
ClientApp->>OktaAuthServer: Request authorization code (via redirect)
OktaAuthServer->>User: Prompt for login and consent
User->>OktaAuthServer: Authenticates and consents
OktaAuthServer->>ClientApp: Redirects back with authorization code
ClientApp->>OktaAuthServer: Exchange authorization code for tokens (access, ID, refresh)
OktaAuthServer->>ClientApp: Issues tokens
ClientApp->>ResourceServer: Request resource with access token
ResourceServer->>OktaAuthServer: Validate access token
OktaAuthServer->>ResourceServer: Token is valid (or invalid)
ResourceServer->>ClientApp: Grant (or deny) access to resource
The core of Okta’s Authorization Server is its ability to define custom authorization servers. These are distinct entities from Okta’s default ones, allowing you to tailor token issuance for specific applications or sets of APIs. When you create a custom authorization server, you define its audiences (the APIs that will trust tokens issued by this server) and scopes (permissions that can be requested).
The real power comes in defining token customization policies. These policies allow you to dynamically add claims to access tokens based on various factors:
- User’s profile: Add attributes like
departmentoremployeeType. - User’s group memberships: Include
groupsclaims. - Client application: Add client-specific identifiers.
- The requested scopes: Dynamically generate claims based on which scopes were granted.
- The requested audience: Tailor claims for specific resource servers.
Here’s a snippet of what a token customization policy might look like in Okta’s UI (conceptual):
Policy Name: Add Department Claim for Internal Apps
Conditions:
- User’s Groups:
Internal Employees - Audience:
https://api.mycompany.com
Actions:
- Add Claim:
- Name:
department - Value:
user.department - Include in token type:
Access Token
- Name:
This means that only users in the Internal Employees group will have a department claim added to their access token when requesting access to https://api.mycompany.com.
The audience is a critical concept. It’s a string that identifies the resource server that the access token is intended for. When a client application requests a token, it specifies the desired audience. The authorization server then ensures that the issued token is only valid for that specific audience. This prevents a token issued for API A from being used to access API B, even if both APIs are protected by Okta.
The scopes are also defined per authorization server and represent granular permissions. A client application requests specific scopes (e.g., read:users, write:orders). The authorization server validates these requested scopes against its configured policies and grants them if authorized. The granted scopes are then typically included in the scp claim within the access token.
The most surprising true thing about Okta’s OAuth2 Authorization Server is its ability to act as a full-fledged identity and access management (IAM) gateway, not just a token issuer. You can leverage its policy engine to enforce complex authorization rules before a token is even issued, effectively offloading much of your application-level authorization logic to Okta. This means your resource servers can often trust the token implicitly for many access decisions, as the Okta Authorization Server has already vetted the request based on dynamic policies.
When you configure an authorization server, you’ll see options for "Default Authorization Server" and "Custom Authorization Servers." The default one is pre-configured for Okta’s own OIDC/OAuth2 flows. Custom ones are where you build out your own API security. You’ll define audiences like api://my-internal-app or https://my-partner-api.com. For scopes, think read:customers, process:payments, admin:users.
When defining claims, you’re essentially telling Okta: "If these conditions are met, add this piece of information to the token." The user.profile.email or user.groups.name are common expressions you’ll see. You can even use Okta Expression Language (OEL) for more advanced transformations. For instance, a claim might be Claims(user.groups.filter(g => g.startsWith("role_")).map(g => g.replace("role_", ""))) to extract only role-related groups.
The next concept you’ll grapple with is how to manage refresh tokens and their rotation, especially in the context of custom authorization servers.