When a user logs in to your app and becomes authenticated, Privy issues the user an app access token. This token is signed by Privy and cannot be spoofed.When your frontend makes a request to your backend, you should include the current user’s access token in the request. This allows your server to determine whether the requesting user is truly authenticated or not.
Privy access tokens are JSON Web Tokens (JWT), signed with the ES256 algorithm. These JWTs include certain information about the user in their claims, namely:
To include the current user’s access token in requests from your frontend to your backend, you’ll first need to retrieve it, then send it appropriately.
React
React Native
Swift
Android
Flutter
Unity
You can get the current user’s Privy token as a string using the getAccessToken method from the usePrivy hook. This method will also automatically refresh the user’s access token if it is nearing expiration or has expired.
If you need to get a user’s Privy token outside of Privy’s React context, you can directly import the getAccessToken method:
Report incorrect code
Copy
Ask AI
import { getAccessToken } from '@privy-io/react-auth';const authToken = await getAccessToken();
When using direct imports, you must ensure PrivyProvider has rendered before invoking the method.
Whenever possible, you should retrieve getAccessToken from the usePrivy hook.
In React Native, you can use the getAccessToken method from the PrivyClient instance to retrieve the user’s access token.
In Swift, you can use the getAccessToken method on the PrivyUser object to retrieve the user’s access token.
Report incorrect code
Copy
Ask AI
// Check if user is authenticatedguard let user = privy.user else { // If user is nil, user is not authenticated return}// Get the access tokendo { let accessToken = try await user.getAccessToken() print("Access token: \(accessToken)")} catch { // Handle error appropriately}
In Android, you can use the getAccessToken method on the PrivyUser object to retrieve the user’s access token.
Report incorrect code
Copy
Ask AI
// Check if user is authenticatedval user = privy.userif (user != null) { // Get the access token val result: Result<String> = user.getAccessToken() // Handle the result with fold method result.fold( onSuccess = { accessToken -> println("Access token: $accessToken") }, onFailure = { error -> // Handle error appropriately }, )}
In Flutter, you can use the getAccessToken method on the PrivyUser object to retrieve the user’s access token.
Report incorrect code
Copy
Ask AI
// Check if user is authenticatedfinal user = privy.user;if (user != null) { // Get the access token final result = await privy.user.getAccessToken(); // Handle the result with fold method result.fold( onSuccess: (accessToken) { print('Access token: $accessToken'); }, onError: (error) { // Handle error appropriately }, );}
In Unity, you can use the GetAccessToken method on the PrivyUser instance to retrieve the user’s access token.
Report incorrect code
Copy
Ask AI
// User will be null if no user is authenticatedPrivyUser user = PrivyManager.Instance.User;if (user != null) { string accessToken = await user.GetAccessToken(); Debug.Log(accessToken);}
If your app is configured to use HTTP-only cookies (instead of the default local storage), the
access token will automatically be included in the cookies for requests to the same domain. In
this case, you don’t need to manually include the token in the request headers.
When your server receives a request, the location of the user’s access token depends on whether your app uses local storage (the default) or cookies to manage user sessions.
Show local storage setup
If you’re using local storage for session management, the access token will be passed in the Authorization header of the request with the Bearer prefix. You can extract it like this:
NodeJS
Go
Python
Report incorrect code
Copy
Ask AI
// Example for Express.jsconst accessToken = req.headers.authorization?.replace('Bearer ', '');// Example for Next.js API routeconst accessToken = req.headers.authorization?.replace('Bearer ', '');// Example for Next.js App Routerconst accessToken = headers().get('authorization')?.replace('Bearer ', '');
Report incorrect code
Copy
Ask AI
// Example for GoaccessToken := r.Header.Get("Authorization")accessToken = strings.Replace(accessToken, "Bearer ", "", 1)
Report incorrect code
Copy
Ask AI
# Example for PythonaccessToken = request.headers.get("Authorization")accessToken = accessToken.replace("Bearer ", "")
Show cookie setup
If you’re using HTTP-only cookies for session management, the access token will be automatically included in the privy-token cookie. You can extract it like this:
NodeJS
Go
Python
Report incorrect code
Copy
Ask AI
// Example for Express.jsconst accessToken = req.cookies['privy-token'];// Example for Next.js API routeconst accessToken = req.cookies['privy-token'];// Example for Next.js App Routerconst cookieStore = cookies();const accessToken = cookieStore.get('privy-token')?.value;
Report incorrect code
Copy
Ask AI
// Example for GoaccessToken := r.Cookies["privy-token"]
Report incorrect code
Copy
Ask AI
# Example for PythonaccessToken = request.cookies.get("privy-token")
Once you’ve obtained the user’s access token from a request, you should verify the token against Privy’s verification key for your app to confirm that the token was issued by Privy and the user referenced by the DID in the token is truly authenticated.The access token is a standard ES256JWT and the verification key is a standard Ed25519 public key. You can verify the access token against the public key using the @privy-io/node or @privy-io/server-auth libraries or using a third-party library for managing tokens.
Pass the user’s access token as a string to the PrivyClient’s verifyAuthToken method:
Report incorrect code
Copy
Ask AI
// `privy` refers to an instance of the `PrivyClient`try { const verifiedClaims = await privy.utils().auth().verifyAuthToken(authToken);} catch (error) { console.log(`Token verification failed with error ${error}.`);}
If the token is valid, verifyAuthToken will return an object with additional information about the request, with the fields below:
Parameter
Type
Description
appId
string
Your Privy app ID.
userId
string
The authenticated user’s Privy DID. Use this to identify the requesting user.
issuer
string
This will always be 'privy.io'.
issuedAt
number
Unix timestamp for when the access token was signed by Privy.
expiration
number
Unix timestamp for when the access token will expire.
sessionId
string
Unique identifier for the user’s session.
If the token is invalid, verifyAuthToken will throw an error and you should not consider the requesting user authorized. This generally occurs if the token has expired or is invalid (e.g. corresponds to a different app ID).
The Privy Client’s verifyAuthToken method will make a request to Privy’s API to fetch the verification key for your app.
You can avoid this API request by copying your verification key from the Configuration > App settings page of the Dashboard.
Report incorrect code
Copy
Ask AI
const privy = new PrivyClient({ appId: 'your-privy-app-id', apiKey: 'your-privy-api-key', // Set the copied verification key to use when creating the `PrivyClient` jwtVerificationKey: 'paste-your-verification-key-from-the-dashboard'});const verifiedClaims = await privy.utils().auth().verifyAuthToken( authToken);
If the JWT is valid, you can extract the JWT’s claims from the payload. For example, you can use payload.sub to get the user’s Privy DID.If the JWT is invalid, this method will throw an error.
The replace operation above ensures that any instances of '\n' in the stringified public key are replaced with actual newlines, per the PEM-encoded format.Lastly, verify the JWT using jwt.verify:
If the JWT is valid, you can extract the JWT’s claims from decoded. For example, you can use decoded.sub to get the user’s Privy DID.If the JWT is invalid, this method will throw an error.
For Go, the golang-jwt library is a popular choice for token verification. To start, install the library:
Report incorrect code
Copy
Ask AI
go get -u github.com/golang-jwt/jwt/v5
Next, load your Privy verification key and app ID as strings:
Then, parse the claims from the JWT and verify that they are valid:
Report incorrect code
Copy
Ask AI
accessToken := "insert-the-users-access-token"// Defining a Go type for Privy JWTstype PrivyClaims struct { AppId string `json:"aud,omitempty"` Expiration uint64 `json:"exp,omitempty"` Issuer string `json:"iss,omitempty"` UserId string `json:"sub,omitempty"`}// This method will be used to check the token's claims laterfunc (c *PrivyClaims) Valid() error { if c.AppId != appId { return errors.New("aud claim must be your Privy App ID.") } if c.Issuer != "privy.io" { return errors.New("iss claim must be 'privy.io'") } if c.Expiration < uint64(time.Now().Unix()) { return errors.New("Token is expired."); } return nil}// This method will be used to load the verification key in the required format laterfunc keyFunc(token *jwt.Token) (interface{}, error) { if token.Method.Alg() != "ES256" { return nil, fmt.Errorf("Unexpected JWT signing method=%v", token.Header["alg"]) } // https://pkg.go.dev/github.com/dgrijalva/jwt-go#ParseECPublicKeyFromPEM return jwt.ParseECPublicKeyFromPEM([]byte(verificationKey)), nil}// Check the JWT signature and decode claims// https://pkg.go.dev/github.com/dgrijalva/jwt-go#ParseWithClaimstoken, err := jwt.ParseWithClaims(accessToken, &PrivyClaims{}, keyFunc)if err != nil { fmt.Println("JWT signature is invalid.")}// Parse the JWT claims into your custom structprivyClaim, ok := token.Claims.(*PrivyClaims)if !ok { fmt.Println("JWT does not have all the necessary claims.")}// Check the JWT claimserr = Valid(privyClaim);if err { fmt.Printf("JWT claims are invalid, with error=%v.", err); fmt.Println();} else { fmt.Println("JWT is valid.") fmt.Printf("%v", privyClaim)}
If the JWT is valid, you can access its claims, including the user’s DID, from the privyClaim struct above.If the JWT is invalid, an error will be thrown.
For Rust, the jsonwebtoken crate is a popular choice for token verification. To start, add it to your dependencies:
Report incorrect code
Copy
Ask AI
[dependencies]jsonwebtoken = "9"serde = { version = "1.0", features = ["derive"] }
Next, load your Privy verification key and app ID as strings:
Report incorrect code
Copy
Ask AI
let verification_key = "insert-your-privy-verification-key";let app_id = "insert-your-privy-app-id";
Then, parse the claims from the JWT and verify that they are valid:
Report incorrect code
Copy
Ask AI
use jsonwebtoken::{decode, DecodingKey, Validation, Algorithm};use serde::{Deserialize, Serialize};let access_token = "insert-the-users-access-token";// Defining a Rust struct for Privy JWTs#[derive(Debug, Serialize, Deserialize)]struct PrivyClaims { aud: String, // App ID exp: u64, // Expiration timestamp iss: String, // Issuer sub: String, // User ID (Privy DID) sid: String, // Session ID iat: u64, // Issued at timestamp}// Configure validation settingslet mut validation = Validation::new(Algorithm::ES256);validation.set_issuer(&["privy.io"]);validation.set_audience(&[app_id]);// Parse the verification keylet decoding_key = DecodingKey::from_ec_pem(verification_key.as_bytes())?;// Verify the JWT and decode claimsmatch decode::<PrivyClaims>(&access_token, &decoding_key, &validation) { Ok(token_data) => { let claims = token_data.claims; println!("JWT is valid"); println!("User ID: {}", claims.sub); println!("App ID: {}", claims.aud); println!("Session ID: {}", claims.sid); // Use the claims for your application logic } Err(err) => { eprintln!("JWT verification failed: {}", err); // Handle invalid token }}
If the JWT is valid, you can access its claims, including the user’s DID, from the claims struct above.If the JWT is invalid, an error will be returned with details about what went wrong.
For Python, use the verify_access_token method to verify the access token and get the user’s claims.
Report incorrect code
Copy
Ask AI
from privy import PrivyAPIclient = PrivyAPI(app_id="your-privy-app-id", app_secret="your-privy-api-key")try: user = client.users.verify_access_token(access_token) print(user)except Exception as e: print(e)
If the token is valid, verify_access_token will return an AccessTokenClaims object with additional information about the request, with the fields below:
Parameter
Type
Description
app_id
string
Your Privy app ID.
user_id
string
The authenticated user’s Privy DID. Use this to identify the requesting user.
issuer
string
This will always be 'privy.io'.
issued_at
string
Timestamp for when the access token was signed by Privy.
expiration
string
Timestamp for when the access token will expire.
session_id
string
Unique identifier for the user’s session.
If the token is invalid, verify_access_token will throw an exception and you should not consider the requesting user authorized. This generally occurs if the token has expired or is invalid (e.g. corresponds to a different app ID).
The Privy Client’s verify_access_token method will make a request to Privy’s API to fetch the verification key for your app. You can avoid this API request by copying your verification key from the Configuration > App settings page of the Dashboard and passing it as a second parameter to verify_access_token:
Report incorrect code
Copy
Ask AI
user = client.users.verify_access_token( access_token, 'paste-your-verification-key-from-the-dashboard')
A user’s access token might expire while they are actively using your app. For example, if a user does not take action on an application for an extended period of time, the access token can become expired.
Handle invalid token errors: In these scenarios, if a method returns with an 'invalid auth token' error, we recommend calling the getAccessToken method with a time-based backoff until the user’s access token is refreshed with an updated expiration time.
Return errors from backend: If you receive an expired access token in your backend, return an error to your client, and as above, trigger getAccessToken in your client.
Handle failed refreshes: If the user’s access token cannot be refreshed, the user will be logged out.