Access user data securely with Privy identity tokens
Identity tokens provide a secure and efficient way to access user data, especially on the server side. These tokens are JSON Web Tokens (JWTs) whose claims contain information about the currently authenticated user, including their linked accounts, metadata, and more.
Privy strongly recommends using identity tokens when you need user-level data on your server. They allow you to easily pass a signed representation of the current user’s linked accounts from your frontend to your backend directly, letting you verifiably determine which accounts (wallet address, email address, Farcaster profile, etc.) are associated with the current request.
Once you’ve enabled identity tokens, Privy will automatically include the identity token as a cookie on every request from your frontend to your server.
For setups where you cannot use cookies, you can retrieve the identity token using the useIdentityToken hook:
Copy
Ask AI
import { useIdentityToken } from '@privy-io/react-auth';function MyComponent() { const { identityToken } = useIdentityToken(); // Use the token in your API requests const callApi = async () => { const response = await fetch('/api/your-endpoint', { headers: { 'privy-id-token': identityToken } }); }; return ( <button onClick={callApi}>Call API</button> );}
We strongly recommend setting a base domain for your application, so that Privy can set the identity token as a more secure HttpOnly cookie.
Once you’ve enabled identity tokens, Privy will automatically include the identity token as a cookie on every request from your frontend to your server.
For setups where you cannot use cookies, you can retrieve the identity token using the useIdentityToken hook:
Copy
Ask AI
import { useIdentityToken } from '@privy-io/react-auth';function MyComponent() { const { identityToken } = useIdentityToken(); // Use the token in your API requests const callApi = async () => { const response = await fetch('/api/your-endpoint', { headers: { 'privy-id-token': identityToken } }); }; return ( <button onClick={callApi}>Call API</button> );}
We strongly recommend setting a base domain for your application, so that Privy can set the identity token as a more secure HttpOnly cookie.
In React Native applications, you can get the current user’s Privy token using the getIdentityToken method from the useIdentityToken hook:
Copy
Ask AI
import { useIdentityToken } from '@privy-io/expo';function MyComponent() { const { getIdentityToken } = useIdentityToken(); const callApi = async () => { const idToken = await getIdentityToken(); // For authenticated users, idToken will be a valid token // For unauthenticated users, idToken will be null if (idToken) { const response = await fetch('https://your-api.com/endpoint', { method: 'POST', headers: { 'privy-id-token': idToken, 'Content-Type': 'application/json' }, body: JSON.stringify({ /* your data */ }) }); } }; return ( <Button onPress={callApi} title="Call API" /> );}
In Swift applications, the identity token can be accessed directly on the PrivyUser object. It will default to nil if it has not been configured. You can grab it with privy.user.identityToken:
Copy
Ask AI
// Check if user is authenticatedguard let user = privy.user else { // If user is nil, user is not authenticated return}// Access the identity tokenif let identityToken = user.identityToken { print("Identity token: \(identityToken)")} else { // Identity token has not been configured, defaults to nil}
In Android applications, the identity token can be accessed directly on the PrivyUser object. It will default to null if it has not been configured. You can grab it with privy.user.identityToken:
Copy
Ask AI
// Check if user is authenticatedval user = privy.userif (user != null) { // Access the identity token val identityToken = user.identityToken if (identityToken != null) { println("Identity token: $identityToken") } else { // Identity token has not been configured, defaults to null }}
In Flutter applications, the identity token can be accessed directly on the PrivyUser object. It will default to null if it has not been configured. You can grab it with privy.user.identityToken:
Copy
Ask AI
// Check if user is authenticatedfinal user = privy.user;if (user != null) { // Access the identity token final identityToken = user.identityToken; if (identityToken != null) { print("Identity token: $identityToken"); } else { // Identity token has not been configured, defaults to null }}
On your server, you can retrieve the identity token from incoming requests and use it to identify the user.
Copy
Ask AI
// pages/api/example.tsimport type { NextApiRequest, NextApiResponse } from 'next';import { getUser } from '@privy-io/server-auth';export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { // Get identity token from cookie const idToken = req.cookies['privy-id-token']; // Or from header if sent that way // const idToken = req.headers['privy-id-token']; if (!idToken) { return res.status(401).json({ message: 'Unauthorized' }); } // Parse and verify the token const user = await getUser({ idToken }); // Now you can use the user data return res.status(200).json({ userId: user.id, // Other user data... }); } catch (error) { console.error('Error verifying identity token:', error); return res.status(401).json({ message: 'Invalid token' }); }}
Copy
Ask AI
// pages/api/example.tsimport type { NextApiRequest, NextApiResponse } from 'next';import { getUser } from '@privy-io/server-auth';export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { // Get identity token from cookie const idToken = req.cookies['privy-id-token']; // Or from header if sent that way // const idToken = req.headers['privy-id-token']; if (!idToken) { return res.status(401).json({ message: 'Unauthorized' }); } // Parse and verify the token const user = await getUser({ idToken }); // Now you can use the user data return res.status(200).json({ userId: user.id, // Other user data... }); } catch (error) { console.error('Error verifying identity token:', error); return res.status(401).json({ message: 'Invalid token' }); }}
Copy
Ask AI
// app/api/example/route.tsimport { cookies, headers } from 'next/headers';import { getUser } from '@privy-io/server-auth';import { NextResponse } from 'next/server';export async function GET() { try { // Get identity token from cookie const cookieStore = cookies(); const idToken = cookieStore.get('privy-id-token')?.value; // Or from header if sent that way // const headersList = headers(); // const idToken = headersList.get('privy-id-token'); if (!idToken) { return NextResponse.json({ message: 'Unauthorized' }, { status: 401 }); } // Parse and verify the token const user = await getUser({ idToken }); // Now you can use the user data return NextResponse.json({ userId: user.id, // Other user data... }); } catch (error) { console.error('Error verifying identity token:', error); return NextResponse.json({ message: 'Invalid token' }, { status: 401 }); }}
Copy
Ask AI
import express from 'express';import cookieParser from 'cookie-parser';import { getUser } from '@privy-io/server-auth';const app = express();app.use(cookieParser());app.get('/api/protected', async (req, res) => { try { // Get identity token from cookie const idToken = req.cookies['privy-id-token']; // Or from header if sent that way // const idToken = req.headers['privy-id-token']; if (!idToken) { return res.status(401).json({ message: 'Unauthorized' }); } // Parse and verify the token const user = await getUser({ idToken }); // Now you can use the user data return res.status(200).json({ userId: user.id, // Other user data... }); } catch (error) { console.error('Error verifying identity token:', error); return res.status(401).json({ message: 'Invalid token' }); }});app.listen(3000, () => { console.log('Server running on port 3000');});
Copy
Ask AI
from privy import PrivyAPIclient = PrivyAPI(app_id="your-privy-app-id", app_secret="your-privy-api-key")user = client.users.get_by_id_token(id_token)print(user)
Privy allows you to set custom metadata for a user via backend API requests. This metadata is available in the custom_metadata claim of the identity token.
Here’s how to parse and access it:
Copy
Ask AI
import {PrivyClient} from '@privy-io/server-auth';import * as jose from 'jose';const client = new PrivyClient(PRIVY_APP_ID, PRIVY_APP_SECRET);// Method 1: Using getUser (recommended)async function getUserWithMetadata(idToken) { const user = await client.getUser({idToken}); // Custom metadata is already parsed and available return user.customMetadata;}// Method 2: Manual parsingasync function parseCustomMetadata(idToken) { const verificationKey = await jose.importJWK(/* your verification key */); try { const {payload} = await jose.jwtVerify(idToken, verificationKey, { issuer: 'privy.io', audience: 'your-privy-app-id' }); if (payload && payload.custom_metadata) { return JSON.parse(payload.custom_metadata); } return {}; } catch (error) { console.error('Error parsing identity token:', error); throw error; }}
When your server receives a request with an identity token, you should verify the token’s signature to authenticate the user. The preferred way is to use the getUser method from @privy-io/server-auth, which handles verification and parsing:
Copy
Ask AI
import {PrivyClient} from '@privy-io/server-auth';const client = new PrivyClient(PRIVY_APP_ID, PRIVY_APP_SECRET);async function verifyAndGetUser(idToken) { try { // This verifies the token signature and parses the payload const user = await client.getUser({idToken}); return user; } catch (error) { console.error('Invalid identity token:', error); throw new Error('Authentication failed'); }}
The verifyAuthToken method will not work on identity tokens, as it is only used to verify Privy
access tokens. Always use getUser({idToken}) when working with identity tokens.
For manual verification without using getUser, you can use JWT libraries like jose:
Copy
Ask AI
import * as jose from 'jose';async function verifyIdentityToken(idToken) { // Import the public key const publicKey = await jose.importJWK({ // Your public key in JWK format }); try { // Verify the token const {payload} = await jose.jwtVerify(idToken, publicKey, { issuer: 'privy.io', audience: 'your-privy-app-id' }); return payload; } catch (error) { console.error('Token verification failed:', error); throw new Error('Authentication failed'); }}