Configure a provider
Enable one of the external-auth integrations in the project dashboard and configure its issuer and JWKS settings:
The repository includes standalone examples for each provider:
examples/workos-integration-demoexamples/better-auth-integration-demoexamples/clerk-integration-demo
Token claims
Every provider token must contain:sub: the provider user identifiersid: the provider session identifierexp: the token expiration time
email, name, and email_verified are optional. Hexclave maps valid email and name claims when it creates the user. It marks the email verified only when email_verified is true.
The default claim sets differ by provider:
To map Clerk profile data, add the claims to Clerk’s session token. See Add profile claims to the Clerk session token. To map WorkOS profile data, add the claims with a WorkOS JWT template. See Add profile claims to the WorkOS access token.
Claims are mapped only when the Hexclave user is first created. Later exchanges do not overwrite the user’s existing display name or email, so adding claims later does not update users that already exist. A provider email is stored as unverified unless the provider asserts
email_verified: true (the boolean, not the string "true"); it never enables Hexclave password or OTP authentication.
Set up Clerk in a Next.js app
This walkthrough assumes a Next.js app that already uses@clerk/nextjs for sign-in. Clerk keeps owning the session; Hexclave asks Clerk for the current session token and exchanges it for a short-lived Hexclave access token, so there is no separate Hexclave sign-in step.
1
Enable and configure the integration
In the project dashboard, enable Clerk Integration and fill in the provider configuration:
- Issuer: your Clerk instance’s Frontend API URL, for example
https://<your-instance>.clerk.accounts.dev. It must exactly match theissclaim of the Clerk token. - Authorized parties (optional): the origins your app runs on, for example
http://localhost:3000. When set, the token’sazpclaim must match one of them.
2
Add profile claims to the Clerk session token
See the section below. Skip this step if you do not need the user’s email and name in Hexclave.
3
Connect Hexclave to the Clerk session
Create a The
HexclaveClientApp whose token store reads from Clerk, and use it wherever you need the Hexclave user:NEXT_PUBLIC_HEXCLAVE_* values come from your project; the API URL is http://localhost:8102 against a local development environment.The SDK keeps the token store’s subscribe subscription for as long as the token store lives and never unsubscribes it, so each HexclaveClientApp you create leaves one Clerk listener behind. Mount this component once near the root of your app (not in a route that remounts) so that only one app is created.@clerk/nextjs 7 removed <SignedIn> and <SignedOut>. Use <Show when="signed-in"> and <Show when="signed-out"> to switch the UI by sign-in state. ClerkProvider also needs clerkMiddleware; see Clerk’s quickstart for the middleware setup.Add profile claims to the Clerk session token
Clerk’s default session token contains no profile claims, so Hexclave creates the user without an email or name. Add them in the Clerk dashboard under Sessions → Customize session token:clerkTokenStore calls getToken() without a template name, so it receives the session token. A separate Clerk JWT template is not used unless you pass its name to getToken.
Set up WorkOS in a Next.js app
This walkthrough assumes a Next.js app that already uses@workos-inc/authkit-nextjs for sign-in. WorkOS keeps owning the session; Hexclave asks your app for the current WorkOS access token and exchanges it for a short-lived Hexclave access token, so there is no separate Hexclave sign-in step.
1
Enable and configure the integration
In the project dashboard, enable WorkOS Integration and fill in the provider configuration:
- Client ID: your WorkOS client ID (
client_...). Hexclave derives the issuer (https://api.workos.com/user_management/<client-id>) and the JWKS URL from it. The token’sissclaim must match that issuer, and itsclient_idclaim must equal the client ID. - Issuer override (optional): only for a WorkOS deployment whose tokens carry a different
iss. The JWKS URL is always derived from the client ID.
2
Add profile claims to the WorkOS access token
See the section below. Skip this step if you do not need the user’s email and name in Hexclave.
3
Expose the WorkOS access token to the browser
AuthKit keeps the session in an This route returns a live access token to the signed-in user’s own browser. Keep it same-origin, keep
httpOnly cookie, so browser code cannot read the access token. Add a route that returns the current token and session ID. withAuth() refreshes the token when it is close to expiring:app/api/auth/provider-session/route.ts
Cache-Control: no-store, and do not log its response.4
Connect Hexclave to the WorkOS session
Create a Pass
HexclaveClientApp whose token store reads from that route:signedIn from a server component, and key the component by the WorkOS session ID so that switching to a different WorkOS account rebuilds it instead of reusing the previous account’s cached Hexclave session: const { user, sessionId } = await withAuth(); followed by <HexclaveUserCard key={sessionId} signedIn={user != null} />. The NEXT_PUBLIC_HEXCLAVE_* values come from your project; the API URL is http://localhost:8102 against a local development environment.The AuthKit callback URL (
WORKOS_REDIRECT_URI) must be registered in the WorkOS dashboard and match exactly. authkitMiddleware must also run for the routes that call withAuth(); see WorkOS’s Next.js quickstart for the middleware setup.Add profile claims to the WorkOS access token
The default WorkOS access token containssub, sid, client_id, iss, exp, iat, auth_time and jti, plus org_id, role and permissions when they apply. It has no profile claims, so Hexclave creates the user without an email or name. Add them with a JWT template in the WorkOS dashboard under Authentication → Features → JWT Template:
email and name are not reserved claim names, so the template can set them. WorkOS rejects the reserved names iss, sub, exp, iat, nbf and jti.
After signing in again, the claim-name helper described under Troubleshooting lists email and name, and the new Hexclave user has both. The email is stored as unverified unless the token also has email_verified: true as a boolean.
Troubleshooting
The Hexclave user has no email or name
First check which claims Clerk actually sends. This helper lists the claim names (not the values) of the current Clerk token:azp, exp, fva, iat, iss, nbf, sid, sts, sub, v, which has no email or name. Once the session token is customized and you have signed in again, email and name appear in the list.
- If
emailandnameare missing, the Clerk session token customization was not saved or the token predates it. Sign out and sign in again. - If they are present but the Hexclave user is still empty, the user was created before you added the claims. Delete the Hexclave user and sign in again.
provider-session route the same way. Without a JWT template it lists auth_time, client_id, exp, iat, iss, jti, sid, sub (plus org_id, role and permissions when they apply). The same two checks apply: if email and name are missing, the JWT template was not saved or the token predates it; if they are present, delete the existing Hexclave user and sign in again.
The WorkOS token is rejected
The exchange fails when the token’siss does not equal the issuer derived from the configured client ID, or when its client_id claim differs from that client ID. Check that the client ID in the dashboard belongs to the same WorkOS environment (staging or production) that issues your tokens. If your WorkOS deployment issues tokens with a different iss, set the Issuer override.
The Hexclave panel never leaves its loading state
Build theHexclaveClientApp only after Clerk reports isLoaded from useAuth(). clerk.loaded is a plain property on a long-lived object, so reading it in useMemo does not re-run when Clerk finishes loading.
Sessions and sign-out
A fresh, valid provider JWT can re-establish a revoked Hexclave external session. This allows a provider session that is still active to be exchanged again without creating a second Hexclave user. External users must sign out through their provider. Calling Hexclave’s ownsignOut() for an externally authenticated session throws rather than revoking only the Hexclave session. The prebuilt UI therefore hides the unsupported Hexclave sign-out control for external sessions.