Some teams have requirements that make it impractical to use Turnkey’s built-in authentication directly — existing enterprise SSO, compliance constraints, a mature identity platform already in production, or simply a preference to keep auth centralized in one system. In these cases, you don’t need to replace your auth layer: Turnkey can work alongside it. If you already have an authentication system — whether that’s Auth0, Cognito, an enterprise IdP, or a homegrown JWT issuer — you can keep using it to authenticate users and only rely on Turnkey for wallet and key management. The key decision is whether you want that integration to be custodial or non-custodial.Documentation Index
Fetch the complete documentation index at: https://docs.turnkey.com/llms.txt
Use this file to discover all available pages before exploring further.
Custodial vs. non-custodial
Custodial (API key approach)
The simplest integration pattern is to use a parent org API key on your backend. Your server authenticates users however it normally would, and then uses the API key to operate on their Turnkey sub-organization on their behalf. This works well and is easy to implement, but it is custodial: your backend holds signing authority over user wallets. Sub-org provisioning: Your backend generates an API key pair for the user and registers it in the sub-org at creation time. This API key lives in the sub-org and is what your backend uses to stamp all subsequent requests on that user’s behalf.Non-custodial (OIDC approach)
If you want users to fully control their wallets, Turnkey must be able to independently verify that a user has authenticated with your system. This requires your auth system to issue OIDC-compliant tokens, a standard Turnkey knows how to validate. With that in place, the user’s device generates a keypair, receives an OIDC token from your auth system that binds that keypair to their identity, and Turnkey registers the public key as a session credential directly in the sub-org. Sub-org provisioning: Your backend still creates the sub-org (using the parent org API key) on first registration, but includes the user’s OIDC provider in the root user so that the user can authenticate directly with Turnkey on subsequent logins.- Client generates a P256 keypair and computes
nonce = sha256(publicKey) - Client passes the nonce to your auth system when requesting a token
- Auth system issues an OIDC token with that nonce embedded
- Client sends the OIDC token and
publicKeyto your backend - Backend calls
oauthLogin(stamped with the parent org API key) with the OIDC token andpublicKey - Turnkey verifies the token signature and checks that
nonce == sha256(publicKey), then returns a session JWT - Client stores the session — only the device holding the private key can use it to sign
Requirements for your OIDC issuer
To use the non-custodial flow, your auth system must issue OIDC-compliant tokens with standard claims (iss, sub, aud, exp), a publicly reachable /.well-known/openid-configuration endpoint, and a nonce set to sha256(publicKey) to bind the token to the user’s device keypair. See OIDC token verification for the full details on how Turnkey validates tokens.
Integration flow
Step 1: Register the user
When a user first authenticates, create a Turnkey sub-org for them with your OIDC provider registered. Registration requires a valid OIDC token — Turnkey verifies its signature against your JWKS and extracts theiss, sub, and aud claims, storing them as the user’s identity fingerprint. The token itself is not retained; on each subsequent login a fresh token is verified independently and matched against that fingerprint. See Registration vs. login tokens for the full explanation.
Step 2: Log the user in
On each login, the frontend generates a keypair, requests a token withnonce = sha256(publicKey) from your auth server, then calls oauthLogin:
sha256(publicKey). The resulting session JWT is scoped to that public key — only the device holding the private key can use it to sign.
If you are using @turnkey/react-wallet-kit, see Advanced backend authentication for how to wire this up on the frontend. For a working implementation of this flow, see the oauth example in the SDK — it uses Google as the provider, but the client/backend split and nonce binding pattern are identical for any OIDC issuer.
Adding an OIDC provider to an existing user
If a user already has a Turnkey sub-org (created via email OTP, passkey, etc.) and you want to add your OIDC provider to their account, usecreateOauthProviders. This activity must be stamped with a credential that already has authority in that sub-org — for example, the user’s active session, their passkey, or a backend API key registered in the sub-org. The parent org API key alone cannot stamp activities against a sub-org.