Documentation Index
Fetch the complete documentation index at: https://mintlify.com/tkhq/sdk/llms.txt
Use this file to discover all available pages before exploring further.
Turnkey supports multiple authentication methods out of the box. Each method creates or retrieves a sub-organization for the user, then issues a session token used to sign subsequent API requests.
Supported methods:
- Passkeys — WebAuthn-based biometric or hardware key authentication
- Email OTP — one-time passcode sent to the user’s email address
- Phone OTP — one-time passcode sent via SMS
- OAuth — social login via Google, Apple, Facebook, X (Twitter), or Discord
When you use the Auth Proxy (authProxyConfigId), Turnkey’s managed backend handles credential validation, sub-organization creation, and session issuance. You do not need to run your own server for most authentication flows.
Quick authentication
The fastest way to add auth to a React app is handleLogin from the useTurnkey hook. It opens a modal with every method you have enabled in your Auth Proxy Config.
components/LoginButton.tsx
"use client";
import { useTurnkey } from "@turnkey/react-wallet-kit";
export function LoginButton() {
const { handleLogin } = useTurnkey();
return <button onClick={handleLogin}>Log in / Sign up</button>;
}
Authentication methods
Passkeys
Email OTP
OAuth
Phone OTP
Passkeys use the WebAuthn API to authenticate users with biometrics or a hardware security key. Turnkey creates a sub-organization for each user and registers the passkey as an authenticator.Enable passkeys
Set passkeyAuthEnabled: true in TurnkeyProviderConfig.auth.methods:"use client";
import { TurnkeyProvider, TurnkeyProviderConfig } from "@turnkey/react-wallet-kit";
const turnkeyConfig: TurnkeyProviderConfig = {
organizationId: process.env.NEXT_PUBLIC_ORGANIZATION_ID!,
authProxyConfigId: process.env.NEXT_PUBLIC_AUTH_PROXY_CONFIG_ID!,
auth: {
methods: {
passkeyAuthEnabled: true,
},
},
};
export function Providers({ children }: { children: React.ReactNode }) {
return <TurnkeyProvider config={turnkeyConfig}>{children}</TurnkeyProvider>;
}
Add a passkey to an existing account
Once logged in, users can register additional passkeys using handleAddPasskey:components/AddPasskey.tsx
"use client";
import { useTurnkey } from "@turnkey/react-wallet-kit";
export function AddPasskeyButton() {
const { handleAddPasskey } = useTurnkey();
return (
<button
onClick={() =>
handleAddPasskey({
displayName: "My device passkey",
successPageDuration: 2000,
})
}
>
Add passkey
</button>
);
}
Email OTP sends a one-time passcode to the user’s email address. The two-step flow calls sendOtp to deliver the code and verifyOtp to exchange it for a verification token, which is then used to create a session.Enable email OTP
const turnkeyConfig: TurnkeyProviderConfig = {
organizationId: process.env.NEXT_PUBLIC_ORGANIZATION_ID!,
authProxyConfigId: process.env.NEXT_PUBLIC_AUTH_PROXY_CONFIG_ID!,
auth: {
methods: {
emailOtpAuthEnabled: true,
},
},
};
Server actions
If you are running your own backend, use the server object from @turnkey/sdk-server:import { server } from "@turnkey/sdk-server";
// Step 1: send the OTP
const otpResponse = await server.sendOtp({
contact: "user@example.com",
otpType: "OTP_TYPE_EMAIL",
appName: "My App",
});
// otpResponse.otpId is used in the next step
// Step 2: verify the OTP code the user entered
const verifyResponse = await server.verifyOtp({
otpId: otpResponse.otpId,
otpCode: "123456",
});
// verifyResponse.verificationToken is passed to otpLogin
The verificationToken returned by verifyOtp is then passed to otpLogin to issue a session. Turnkey supports OAuth 2.0 / OIDC login with Google, Apple, Facebook, X (Twitter), and Discord. Each provider redirects the user through an authorization flow and returns an OIDC token, which Turnkey exchanges for a session.Enable OAuth providers
const turnkeyConfig: TurnkeyProviderConfig = {
organizationId: process.env.NEXT_PUBLIC_ORGANIZATION_ID!,
authProxyConfigId: process.env.NEXT_PUBLIC_AUTH_PROXY_CONFIG_ID!,
auth: {
methods: {
googleOauthEnabled: true,
appleOauthEnabled: true,
facebookOauthEnabled: true,
xOauthEnabled: true,
discordOauthEnabled: true,
},
oauthConfig: {
oauthRedirectUri: "https://yourdomain.com/oauth/callback",
googleClientId: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID,
appleClientId: process.env.NEXT_PUBLIC_APPLE_CLIENT_ID,
},
},
};
Trigger OAuth manually
You can invoke individual OAuth flows directly from the useTurnkey hook:components/GoogleLogin.tsx
"use client";
import { useTurnkey } from "@turnkey/react-wallet-kit";
export function GoogleLoginButton() {
const { handleGoogleOauth } = useTurnkey();
return (
<button
onClick={() =>
handleGoogleOauth({
clientId: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID,
openInPage: false, // use a popup
})
}
>
Sign in with Google
</button>
);
}
Server-side OAuth login
Once your backend receives the OIDC token, call oauthLogin to create a session:import { server } from "@turnkey/sdk-server";
const sessionResponse = await server.oauthLogin({
suborgID: "<user-suborg-id>",
oidcToken: "<oidc-token-from-provider>",
publicKey: "<ephemeral-public-key>",
sessionLengthSeconds: 900,
});
// sessionResponse.session is the session token
Phone OTP works identically to email OTP, but delivers the code via SMS.Enable SMS OTP
const turnkeyConfig: TurnkeyProviderConfig = {
organizationId: process.env.NEXT_PUBLIC_ORGANIZATION_ID!,
authProxyConfigId: process.env.NEXT_PUBLIC_AUTH_PROXY_CONFIG_ID!,
auth: {
methods: {
smsOtpAuthEnabled: true,
},
},
};
Server actions
import { server } from "@turnkey/sdk-server";
// Send SMS OTP
const otpResponse = await server.sendOtp({
contact: "+15551234567",
otpType: "OTP_TYPE_SMS",
appName: "My App",
});
// Verify the code
const verifyResponse = await server.verifyOtp({
otpId: otpResponse.otpId,
otpCode: "654321",
});
Session management
After a successful authentication, the SDK stores a session token and exposes it through the useTurnkey hook:
components/SessionStatus.tsx
"use client";
import { useTurnkey } from "@turnkey/react-wallet-kit";
export function SessionStatus() {
const { session, authState } = useTurnkey();
if (authState === "unauthenticated") {
return <p>Not logged in.</p>;
}
return <p>Session expires: {session?.expiry}</p>;
}
Session expiration is controlled by auth.sessionExpirationSeconds in your TurnkeyProviderConfig (default: 900 seconds / 15 minutes). When using the Auth Proxy, configure this value through the Turnkey dashboard instead.
To handle session events, add lifecycle callbacks to TurnkeyProvider:
<TurnkeyProvider
config={turnkeyConfig}
callbacks={{
onAuthenticationSuccess: ({ session, action, method, identifier }) => {
console.log("Authenticated via", method, "as", identifier);
},
beforeSessionExpiry: ({ sessionKey }) => {
console.log("Session expiring soon:", sessionKey);
},
onSessionExpired: ({ sessionKey }) => {
console.log("Session expired:", sessionKey);
},
onError: (error) => console.error("Turnkey error:", error),
}}
>
{children}
</TurnkeyProvider>
Server-side session validation
Use TurnkeyServerClient from @turnkey/sdk-server to verify sessions or perform privileged operations on the server:
import { TurnkeyServerClient } from "@turnkey/sdk-server";
const client = new TurnkeyServerClient({
stamper: myStamper, // ApiKeyStamper or equivalent
apiBaseUrl: "https://api.turnkey.com",
organizationId: process.env.TURNKEY_ORGANIZATION_ID!,
});
// Use the client to call any Turnkey API method
const user = await client.getUser({
organizationId: suborgsOrganizationId,
userId: sessionUserId,
});
Auth method configuration reference
All authentication options are set under auth.methods in TurnkeyProviderConfig:
| Option | Type | Description |
|---|
emailOtpAuthEnabled | boolean | Enable email OTP login |
smsOtpAuthEnabled | boolean | Enable SMS OTP login |
passkeyAuthEnabled | boolean | Enable passkey (WebAuthn) login |
walletAuthEnabled | boolean | Enable wallet-based login |
googleOauthEnabled | boolean | Enable Google OAuth |
appleOauthEnabled | boolean | Enable Apple OAuth |
facebookOauthEnabled | boolean | Enable Facebook OAuth |
xOauthEnabled | boolean | Enable X (Twitter) OAuth |
discordOauthEnabled | boolean | Enable Discord OAuth |