> Discover all available pages from the documentation index: https://mastra.ai/llms.txt # Okta The `@mastra/auth-okta` package provides authentication and role-based access control for Mastra using Okta. It supports an OAuth 2.0 / OIDC login flow with encrypted session cookies and maps Okta groups to Mastra permissions. ## Prerequisites This guide uses Okta authentication. Make sure to: 1. Create an Okta account at [okta.com](https://www.okta.com/) 2. Set up an OAuth application in the Okta Admin Console (Web app, Authorization Code grant) 3. Add your redirect URI to the application's sign-in redirect URIs 4. Create an API token (required for RBAC) Make sure your environment variables are set. ```env OKTA_DOMAIN=dev-123456.okta.com OKTA_CLIENT_ID=your-client-id OKTA_CLIENT_SECRET=your-client-secret OKTA_REDIRECT_URI=http://localhost:4111/api/auth/callback OKTA_COOKIE_PASSWORD=a-random-string-at-least-32-characters-long OKTA_API_TOKEN=your-api-token ``` > **Note:** `OKTA_COOKIE_PASSWORD` encrypts session cookies. If omitted, an auto-generated value is used that doesn't survive server restarts. Set it explicitly for production. > > `OKTA_API_TOKEN` is only required when using `MastraRBACOkta` to map Okta groups to permissions. ## Installation **npm**: ```bash npm install @mastra/auth-okta ``` **pnpm**: ```bash pnpm add @mastra/auth-okta ``` **Yarn**: ```bash yarn add @mastra/auth-okta ``` **Bun**: ```bash bun add @mastra/auth-okta ``` ## Usage examples ### Basic usage with environment variables With the environment variables above set, all constructor parameters are optional: ```typescript import { Mastra } from '@mastra/core' import { MastraAuthOkta } from '@mastra/auth-okta' export const mastra = new Mastra({ server: { auth: new MastraAuthOkta(), }, }) ``` ### Auth with RBAC Add `MastraRBACOkta` to map Okta groups to Mastra permissions: ```typescript import { Mastra } from '@mastra/core' import { MastraAuthOkta, MastraRBACOkta } from '@mastra/auth-okta' export const mastra = new Mastra({ server: { auth: new MastraAuthOkta(), rbac: new MastraRBACOkta({ roleMapping: { Admin: ['*'], Engineering: ['agents:*', 'workflows:*', 'tools:*'], Viewer: ['agents:read', 'workflows:read'], _default: [], // users with unmapped groups get no permissions }, }), }, }) ``` ### Cross-provider usage Use a different auth provider (Auth0, Clerk, etc.) for login and Okta for RBAC. Pass a `getUserId` function to resolve the Okta user ID from the other provider's user object: ```typescript import { Mastra } from '@mastra/core' import { MastraAuthAuth0 } from '@mastra/auth-auth0' import { MastraRBACOkta } from '@mastra/auth-okta' export const mastra = new Mastra({ server: { auth: new MastraAuthAuth0(), rbac: new MastraRBACOkta({ getUserId: user => user.metadata?.oktaUserId || user.email, roleMapping: { Engineering: ['agents:*', 'workflows:*'], Admin: ['*'], _default: [], }, }), }, }) ``` > **Note:** To link users between providers, store the Okta user ID in the other provider's user metadata. Mastra uses this ID to fetch groups from Okta. Visit [MastraAuthOkta](https://mastra.ai/reference/auth/okta) for all available configuration options. ## Role mapping The `roleMapping` option maps Okta group names to arrays of Mastra permission strings. Permissions follow a `resource:action` pattern and support wildcards: ```typescript const rbac = new MastraRBACOkta({ roleMapping: { // full access to everything Admin: ['*'], // full access to agents and workflows Engineering: ['agents:*', 'workflows:*'], // read-only access Viewer: ['agents:read', 'workflows:read'], // users whose groups don't match any key above _default: [], }, }) ``` The `_default` key assigns permissions to users whose Okta groups don't match any other key. ## Client-side setup When auth is enabled, requests to Mastra routes require authentication. `MastraAuthOkta` uses SSO, so users authenticate through Okta's hosted login page. After login, an encrypted session cookie is set automatically. ### Cookie session (recommended) For cross-origin requests (e.g. a frontend on `:3000` calling Mastra on `:4111`), enable CORS credentials on the Mastra server: ```typescript export const mastra = new Mastra({ server: { auth: new MastraAuthOkta(), cors: { origin: 'http://localhost:3000', credentials: true, }, }, }) ``` Configure the client to include credentials: ```typescript import { MastraClient } from '@mastra/client-js' export const mastraClient = new MastraClient({ baseUrl: 'http://localhost:4111', credentials: 'include', }) ``` ### Bearer token You can also pass an Okta token as a Bearer token. The token is verified against Okta's JWKS endpoint, and its `aud` claim must match the configured audience. The audience defaults to your client ID, and you can override it with the `audience` option or `OKTA_AUDIENCE`. Okta puts the client ID in the `aud` claim of **ID tokens**, so ID tokens work with the default. **Access tokens** carry the audience of the authorization server that issued them, so set the audience to match: - **Org authorization server** (the default, issuer `https://{domain}`): set the audience to `https://{domain}`. - **Custom authorization server** (issuer `https://{domain}/oauth2/{name}`): set the audience to the server's audience value from the Okta Admin Console, for example `api://default`. ```env OKTA_AUDIENCE=https://dev-123456.okta.com ``` Pass an array to accept more than one audience, for example ID tokens from browsers and access tokens from service callers against the same provider: ```typescript new MastraAuthOkta({ audience: ['your-client-id', 'https://dev-123456.okta.com'], }) ``` > **Note:** `audience` applies only to Bearer tokens. The ID token exchanged during the SSO login flow is always verified against your client ID. ```typescript import { MastraClient } from '@mastra/client-js' export const createMastraClient = (token: string) => { return new MastraClient({ baseUrl: 'http://localhost:4111', headers: { Authorization: `Bearer ${token}`, }, }) } ``` Visit [Mastra Client SDK](https://mastra.ai/docs/server/mastra-client) for more configuration options. ### Making authenticated requests **MastraClient**: ```typescript import { mastraClient } from '../lib/mastra-client' const agent = mastraClient.getAgent('weatherAgent') const response = await agent.generate('Weather in London') console.log(response) ``` **cURL**: ```bash curl -X POST http://localhost:4111/api/agents/weatherAgent/generate \ -H "Content-Type: application/json" \ -H "Authorization: Bearer " \ -d '{ "messages": "Weather in London" }' ``` ## Troubleshooting - **401 on every request**: Verify your Okta domain, client ID, and client secret are correct. Check that the redirect URI in your Okta application matches `OKTA_REDIRECT_URI`. - **401 with `unexpected "aud" claim value` in the server logs**: The Bearer token's audience doesn't match the configured audience. This usually means you sent an access token while the audience is still the default client ID. Set `OKTA_AUDIENCE` to the audience of the authorization server that issued the token. See [Bearer token](#bearer-token). - **Cookies not sent cross-origin**: Set `credentials: "include"` in `MastraClient` and configure `server.cors` with your frontend origin and `credentials: true`. - **Session lost on restart**: Set `OKTA_COOKIE_PASSWORD` to a stable value (at least 32 characters). Without it, an auto-generated key is used that changes on each restart. - **RBAC returns empty permissions**: Verify `OKTA_API_TOKEN` is set and the token has permission to list user groups. Check that group names in `roleMapping` match your Okta group names exactly.