Guide for setting up a secure backend proxy with Turnkey authentication, focusing on JWT implementation and user data management.
Handling API Lookup Results
const subOrgId = organizationIds[0];
) simply takes the first ID found. This approach might not be suitable for all applications.subOrgId
via email lookup is only the first step and does not grant access. Your application must authenticate the user (e.g., via passkey) after the lookup. Only then should you verify if the authenticated user is authorized for that subOrgId
, typically by checking your user database. Blindly trusting the lookup result is insecure.organizationIds
is empty, it might indicate the user doesn’t have an existing sub-organization. Your application should handle this, potentially by initiating a signup flow or failing the login.Client-side
Send to Backend
Backend Verification
Client-side
Backend Processing
sendOtp
. Turnkey emails the code to the user. The user enters the code in the frontend, which sends it (along with identifiers) to your backend. Your backend then calls verifyOtp
. Upon successful Turnkey verification, your backend issues its own application JWT to manage the proxied session.
Note: This flow generally assumes the user and their associated Turnkey Sub-Organization already exist, as it’s primarily for authentication rather than initial signup.
Request OTP
targetPublicKey
) and sends both to the backend. The backend finds the user’s sub-organization and asks Turnkey to send the OTP email by calling sendOtp
, passing the iframe’s public key as the targetPublicKey
parameter (used by Turnkey for credential encryption upon successful verification).Verify OTP & Issue Backend JWT
targetPublicKey
for encryption) and sends the code, email, original otpId
, and targetPublicKey
to the backend. The backend asks Turnkey to verify the code using verifyOtp
. If successful, the backend generates and sets its own application session JWT cookie and returns the authSession
object from Turnkey to the frontend. The frontend then uses this authSession
to establish the Turnkey session within the iframe via loginWithSession
.userId
from the JWT) is actually authorized to perform the requested action on the target Turnkey sub-organization (subOrgId
). This applies to both write operations (like signing transactions) and read operations (like fetching balances or activities).
Simply verifying the JWT authenticates the user, but it doesn’t authorize them for a specific sub-organization. Your backend must:
userId
.subOrgId
(s) associated with that userId
in your application’s database.subOrgId
from the incoming request against the one
associated with the authenticated user in your database.subOrgId
matches the one(s) associated with the authenticated user.