Integrationssign-in providers
WorkOS AuthKit and Connect tokens
Accept WorkOS AuthKit session tokens and Connect access tokens on Mayura's server with @mayurajs/auth-workos: checks, machines and errors.
- Package
- @mayurajs/auth-workos
- Install
- npm install mayura @mayurajs/auth-workos
- Vendor
- WorkOS ↗
WorkOS AuthKit signs users in to your application, with organizations, roles and enterprise SSO,
and Connect issues OAuth access tokens, also to machines. @mayurajs/auth-workos turns AuthKit session tokens, and
optionally Connect access tokens, into identities for Mayura's server; your identity mapping decides what each holder
may do. It verifies tokens with mayura/auth's own JWT verifier (WebCrypto only): no WorkOS SDK, no dependency, and
it runs on every runtime Mayura runs on.
Install
npm install mayura @mayurajs/auth-workosCredentials
Nothing secret is needed: only your environment's client ID (client_...), shown in the
WorkOS dashboard under API Keys. To accept Connect tokens too, also give your
AuthKit domain, such as https://acme.authkit.app, shown on the dashboard's AuthKit settings. The package reads
nothing from the environment: pass the values in yourself, for example from WORKOS_CLIENT_ID and
WORKOS_AUTHKIT_DOMAIN.
Use it
import { mapCapabilities, principalId } from 'mayura/auth';
import { workosAuthenticator } from '@mayurajs/auth-workos';
export const authenticate = workosAuthenticator({
clientId: process.env.WORKOS_CLIENT_ID ?? '',
connect: { domain: process.env.WORKOS_AUTHKIT_DOMAIN ?? '' }, // optional: Connect tokens too
identity: session => session.orgId ? {
principalId: principalId('workos', session.subject),
projectId: session.orgId,
agentIds: ['support'],
capabilities: mapCapabilities(session.kind === 'authkit' ? session.permissions : session.scopes, {
'agents:use': ['runs:submit', 'runs:read'],
}),
} : null,
});
// createAgentServer({ ..., authenticate })Your frontend sends the AuthKit access token (or a client sends its Connect access token) as the bearer token.
Options
| Option | Default | Meaning |
|---|---|---|
clientId |
required | Your WorkOS client ID, client_ and 6 to 64 letters or digits. |
identity |
required | What a token's holder may do, or null to refuse. |
issuer |
https://api.workos.com/ |
The issuer of AuthKit session tokens: your custom auth domain, if you set one (an https URL, compared as given). |
connect |
none | { domain, audience }: also accept Connect access tokens from your AuthKit domain (https). audience is your client ID by default, or your resource indicators. |
allowMachines |
false |
Accept Connect tokens a machine holds (client credentials). |
clockSkewMs |
5 s | Clock difference allowed for exp, nbf and iat. At most 60 s. |
maxIdentityMs |
60 s | The longest an identity lasts before the token is checked again (1 s to 1 hour). |
fetch |
globalThis.fetch |
For tests and proxies: the fetch used for the JWKS. |
What is checked
- AuthKit session tokens. RS256, issued by
issuer(with the trailing slash AuthKit writes onhttps://api.workos.com/), verified only with the keys WorkOS publishes for your client athttps://api.workos.com/sso/jwks/<clientId>. They carry no audience. - Connect tokens (with
connect). RS256, issued by your AuthKit domain's origin foraudience, verified with the keys at<domain>/oauth2/jwks. A token with no consent (sid) whose subject is its ownclient_idis a machine's, and is refused unlessallowMachines. - Times and subject. Every token must carry
expand be unexpired, withclockSkewMsof leeway, and have asub. - Only the keys of a token's own issuer are fetched, so a token naming another issuer never makes it fetch. When your custom auth domain is also your AuthKit domain, a token is checked as an AuthKit token first, then as a Connect token.
Fetched keys are kept as described in Tokens from an identity provider.
What identity receives
| Field | From |
|---|---|
kind |
authkit for a session token, connect for a Connect token. |
subject |
sub: the user, or a machine's client ID. |
machine |
true for a Connect client credentials token. |
sessionId |
sid: the AuthKit session, or the Connect consent; null if absent. |
clientId |
client_id (Connect), or null. |
orgId |
org_id: the organization selected at sign-in, or a machine's; null if absent. |
role, roles |
role, and roles (or [role] when only role is given). |
permissions |
permissions (AuthKit). |
scopes |
scope, split on spaces (Connect). |
claims |
The verified claims. |
workosSession(claims, kind) is exported for checks of your own.
Errors
| What happens | Result |
|---|---|
A configuration mistake: a malformed clientId, an issuer or connect.domain that is not an https URL, a non-boolean allowMachines, maxIdentityMs out of range |
workosAuthenticator() throws MayuraError INVALID_CONFIG. |
The token fails any check, is a machine's without allowMachines, or identity returns null |
authenticate returns null; the server answers 401 AUTH_INVALID. |
| The JWKS cannot be fetched and no keys are cached (or they are over 10 minutes past their age) | MayuraError TOOL_FAILED; the server answers 503 AUTH_UNAVAILABLE. |
identity returns ids or capabilities the server cannot use |
MayuraError INVALID_CONFIG; the server answers 503 AUTH_UNAVAILABLE, never lets the caller in. |
How it is tested
- Unit tests sign real RS256 tokens for both kinds and serve both JWKS URLs through a fake
fetch. They check that AuthKit tokens read the organization, role and permissions, that other issuers and keys are refused, that Connect tokens are refused unlessconnectis set, that only the token's own issuer's keys are fetched, that machines needallowMachines, and that a shared custom domain accepts both kinds. scripts/live/auth-workos.mjsfetched and checked WorkOS's published signing keys on October 6, 2026. A real token has not been verified with it yet.
Related
- Authentication and API keys: the verifier, key caching and identity mapping.
- Server and client: capabilities and auth errors.
- Clerk session tokens and Okta access tokens: other hosted sign-in.