# 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 does not 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. > **Info:** 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 do not 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 access token as a Bearer token. The token is verified against Okta's JWKS endpoint: ```typescript import { MastraClient } from '@mastra/client-js' export const createMastraClient = (accessToken: string) => { return new MastraClient({ baseUrl: 'http://localhost:4111', headers: { Authorization: `Bearer ${accessToken}`, }, }) } ``` > **Info:** 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`. - **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.