Skip to main content

Overview

Use this guide if you want to run authentication through your own server instead of Turnkey’s Auth Proxy. Your backend will call Turnkey’s public API for OTP, OAuth, and signup. The Swift SDK will:
  • Generate and protect the on-device API key pair
  • Create or resume sessions
  • Persist and expose session/user/wallet state via TurnkeyContext
If you prefer a no-backend setup, use the Auth Proxy instead.

What you can’t use

The following high-level helpers on TurnkeyContext are designed for the Auth Proxy and will throw missingAuthProxyConfiguration when the proxy is disabled:
  • initOtp, verifyOtp, completeOtp
  • handleGoogleOAuth, handleAppleOAuth, handleDiscordOAuth, handleXOauth
  • signUpWithPasskey
For a backend flow, your app talks to your server for OTP/OAuth/signup and only stores the resulting session locally.

Disable the Auth Proxy

Omit authProxyConfigId when configuring the SDK:
With the proxy disabled, TurnkeyContext.client will be stamper-only after you create/store a session.

On your backend

Implement endpoints that forward to Turnkey’s public API. Depending on your flow, you’ll typically use: Notes:
  • Passkey and external wallet login happen on-device via login-with-a-stamp. Signup still requires createSubOrganization on your backend.
  • You may apply custom validation, logging, and rate limiting in your server.
For a complete server example, see the Swift demo wallet’s example server in the Swift SDK repo: swift-sdk/Examples/with-backend/example-server.

Minimal Node/Express signup endpoint

Turnkey also offers Rust and Go SDKs that can be used to implement the backend endpoints. You can also use any other backend language you prefer as long as it can make HTTP requests to the Turnkey API.

On your iOS app

In your iOS app, you will need to implement your own authentication flows that interact with your backend endpoints.

Create a key pair

Login endpoints like otpLogin and oauthLogin will require a public key to be passed in the request. You can use createKeyPair from the TurnkeyContext to generate a keypair for this purpose.
The private key will be generated in the Secure Enclave if available, otherwise it will be generated then securely stored within the Keychain. The public key will be returned and can be passed to your backend.

Store the session returned by your backend

Your backend will return a session JWT. Store it locally so the SDK can manage future stamps automatically:
After that, TurnkeyContext.shared.client is ready for signed API calls, and authState will be .authenticated. If you have autoRefreshSession enabled under the auth object in the TurnkeyConfig configuration, the SDK will automatically refresh the session token when it expires. You can also use the authState variable from the TurnkeyContext to check if the user is authenticated.

Example: OTP login

Putting it all together, you can implement an OTP login flow like this:
OtpLoginView.swift