A React + TypeScript app for testing Auth0 authentication and CDP Developer-Delegated JWT integration.
This app demonstrates the authentication flow for integrating Auth0 with Coinbase Developer Platform (CDP) Embedded Wallets using developer-delegated authentication. It shows:
- How to authenticate users with Auth0
- How JWTs are structured (ID tokens vs Access tokens)
- What claims CDP will receive and validate
- The raw JWT access token that will be sent to CDP APIs
- React 19 with TypeScript
- Vite - Build tool and dev server
- Auth0 React SDK - Authentication
- React Router - Routing
- User logs in via Auth0 (email/password, social, etc.)
- Auth0 issues:
- ID Token - Contains user profile (name, email, picture)
- Access Token - Contains claims for API authorization
- Access token is signed with RS256 and includes custom
audience - CDP will validate the JWT using Auth0's JWKS endpoint
ID Token - Proves who the user is
- Audience: Your Auth0 Client ID
- Contains: User profile information
- Used for: Displaying user info in your app
Access Token - Authorizes API access
- Audience: Your API identifier (e.g.,
test-app) - Contains: Authorization claims, scopes, user ID (
sub) - Used for: Calling protected APIs (like CDP)
JWKS URL - Public keys for JWT validation
https://{your-auth0-domain}/.well-known/jwks.json
Create .env file (copy from .env.example):
VITE_AUTH0_DOMAIN=your-auth0-domain.auth0.com
VITE_AUTH0_CLIENT_ID=your-auth0-client-id- Go to Auth0 Dashboard
- Applications → Create Application
- Choose Single Page Application
- Configure:
- Allowed Callback URLs:
http://localhost:3000 - Allowed Logout URLs:
http://localhost:3000 - Allowed Web Origins:
http://localhost:3000
- Allowed Callback URLs:
- Applications → APIs → Create API
- Configure:
- Name:
CDP Test App(or your choice) - Identifier:
test-app(this becomes theaudclaim) - Signing Algorithm: RS256
- Name:
This API identifier must match the audience in src/main.tsx.
To avoid the consent screen on every login:
- Go to your application settings
- Advanced Settings → OAuth
- Enable "Allow Skipping User Consent"
npm installnpm run dev- Welcome screen with login button
- User Profile - Picture, name, email from Auth0
- User Object - Full ID token claims (left card)
- JWT Claims - Access token claims that CDP will validate (right card)
iss- Issuer (your Auth0 domain)sub- User ID (unique identifier)exp- Expiration timestampiat- Issued at timestampaud- Audience (your API identifier, optional)
- Access Token - Raw JWT string to send to CDP APIs
When configuring CDP's developer-delegated authentication, you'll need:
JWKS URL:
https://dev-example.us.auth0.com/.well-known/jwks.json
Expected Claims:
iss:https://dev-example.us.auth0.com/aud:test-app(or your API identifier)sub: Unique user identifier from Auth0
Signing Algorithm: RS256
src/main.tsx - Auth0 configuration
<Auth0Provider
domain={import.meta.env.VITE_AUTH0_DOMAIN}
clientId={import.meta.env.VITE_AUTH0_CLIENT_ID}
authorizationParams={{
redirect_uri: window.location.origin,
audience: 'test-app',
scope: 'openid profile email'
}}
>src/App.tsx - Fetches and decodes JWT
const token = await getAccessTokenSilently()
const payload = token.split('.')[1]
const claims = JSON.parse(atob(payload))This app supports multiple blockchain wallet types: Solana, EVM EOA, and EVM Smart Accounts.
Currently configured for Solana wallets (see src/main.tsx line 19).
Edit src/main.tsx and update the CDPHooksProvider config:
<CDPHooksProvider
config={{
projectId: import.meta.env.VITE_CDP_PROJECT_ID,
basePath: import.meta.env.VITE_CDP_BASE_PATH,
customAuth: {
getJwt: getAccessTokenSilently
},
solana: { createOnLogin: true }
}}
><CDPHooksProvider
config={{
projectId: import.meta.env.VITE_CDP_PROJECT_ID,
basePath: import.meta.env.VITE_CDP_BASE_PATH,
customAuth: {
getJwt: getAccessTokenSilently
},
ethereum: {
createOnLogin: 'eoa'
}
}}
><CDPHooksProvider
config={{
projectId: import.meta.env.VITE_CDP_PROJECT_ID,
basePath: import.meta.env.VITE_CDP_BASE_PATH,
customAuth: {
getJwt: getAccessTokenSilently
},
ethereum: {
createOnLogin: 'smart'
}
}}
><CDPHooksProvider
config={{
projectId: import.meta.env.VITE_CDP_PROJECT_ID,
basePath: import.meta.env.VITE_CDP_BASE_PATH,
customAuth: {
getJwt: getAccessTokenSilently
},
ethereum: {
createOnLogin: 'eoa' // or 'smart'
},
solana: {
createOnLogin: true
}
}}
>The app will automatically:
- Create the appropriate wallet type(s) during authentication
- Display the correct wallet information cards
- Show the appropriate wallet action buttons:
- Solana: Sign Message, Sign Transaction, Send Transaction
- EVM (EOA/Smart): Sign Message, Send Transaction
- Update the config in
src/main.tsx - Restart the dev server:
npm run dev - Log out and log back in with Auth0
- Click "Authenticate with CDP" to create the new wallet type
- Solana: Uses
solana-devnet - EVM: Uses
base-sepoliatestnet
You can modify the network in:
src/components/SolanaWalletActions.tsx(line 103)src/components/EvmWalletActions.tsx(line 48)