Integrate your existing authentication provider and add smart wallet functionality to your app without changing your users' login experience. Smart Wallets supports JWT-based and OIDC-compliant authentication providers.
Before implementing JWT authentication, verify that your authentication system meets these requirements:
Your authentication system must be OpenID Connect (OIDC) compliant and capable of issuing JWT tokens.
OpenID Connect Discovery Endpoint
Host a discovery endpoint at: <YOUR_API_DOMAIN>/.well-known/openid-configuration
The response must include these required fields from the OpenID spec:
{
"issuer": "<YOUR_API_DOMAIN>",
"jwks_uri": "<YOUR_JWKS_ENDPOINT_URL>",
"id_token_signing_alg_values_supported": ["RS256"],
"authorization_endpoint": "<YOUR_AUTH_ENDPOINT>",
"response_types_supported": ["<YOUR_SUPPORTED_RESPONSE_TYPE>"],
"subject_types_supported": ["<YOUR_SUPPORTED_SUBJECT_TYPE>"]
}Field explanations:
issuer: Your API domain (must match theissclaim in your JWTs)jwks_uri: Endpoint URL where the JWT public key can be retrieved for verificationid_token_signing_alg_values_supported: Must include "RS256" algorithm
JWT Header Requirements
Your JWT header must include:
| Field | Description | Example |
|---|---|---|
alg | Algorithm used to sign the JWT | "RS256" |
typ | Token type | "JWT" |
kid | Key ID that matches the kid field from your JWKs URI | "key-1" |
Important: The kid field in the JWT header must correspond to a key identifier from your JWKS endpoint to enable proper key lookup during token verification.
JWT Payload Requirements
Your JWTs must contain these claims:
| Claim | Description | Example |
|---|---|---|
iss | Issuer - your auth provider's API domain | "https://auth.example.com" |
sub | Subject - unique user identifier | "user123" or "550e8400-e29b-41d4-a716-446655440000" |
aud | Audience - client ID issued by Alchemy | "your-alchemy-audience-id" |
nonce | Target public key hash (see below) | "a1b2c3d4..." |
Important: The nonce claim must be toHex(sha256(targetPublicKey)) without the leading 0x.
Generate the targetPublicKey from the authentication
SDK.
If your OAuth provider reserves the nonce claim, you can use tknonce as an
alternative. Only one of nonce or tknonce needs to be set.
The combination of (iss, sub, aud) acts as a unique user identifier.
Ensure these values are consistent for each user.
The aud claim must be set to the audience ID provided in your Smart Wallet settings. Obtain the audience claim from the dashboard.
npm install @account-kit/signer @account-kit/reactBefore creating your JWT, generate the required targetPublicKey:
import { AlchemySignerWebClient } from "@account-kit/signer";
import { sha256, stringToBytes } from 'viem'
const client = new AlchemySignerWebClient({
connection: {
apiKey: "your-api-key",
},
iframeConfig: {
iframeContainerId: "signer-iframe-container",
},
});
// Generate the target public key
const targetPublicKey = await client.targetPublicKey();
// Use this in your JWT's nonce claim
const nonce = sha256(stringToBytes(targetPublicKey)).slice(2)After generating your JWT with the proper claims, authenticate the user:
import { useAuthenticate } from "@account-kit/react";
// Inside your component
const { authenticate, isPending } = useAuthenticate();
const handleJwtAuth = async (jwt: string) => {
try {
await authenticate({
type: "custom-jwt",
jwt // Your generated JWT with required claims
});
} catch (error) {
console.error("Authentication failed:", error);
}
};Monitor authentication status and handle the connected user:
import { useSignerStatus, useUser } from "@account-kit/react";
const MyComponent = () => {
const { isConnected } = useSignerStatus();
const user = useUser();
if (isConnected && user) {
return (
<div>
<p>Welcome, {user.email}!</p>
<p>Wallet Address: {user.address}</p>
</div>
);
}
return <div>Not authenticated</div>;
};The JWT authentication flow works as follows:
- User Authentication: User logs into your existing auth system
- JWT Generation: Your backend generates a JWT with required claims
- Submit JWT: Frontend submits JWT to the auth endpoint
- Verification: The JWT is verified using your JWKS endpoint
- Wallet Access: User gains access to their smart wallet
sequenceDiagram
participant User
participant YourApp as Your Application
participant YourAuth as Your Auth System
participant Alchemy as Alchemy API
User->>YourApp: Login request
YourApp->>YourAuth: Authenticate user
YourAuth->>YourApp: Return JWT
YourApp->>Alchemy: Submit JWT (/v1/auth-jwt)
Alchemy->>YourApp: Verify JWT and return credentials/wallet info
YourApp->>User: Wallet readyUse jwt.io to decode and validate your JWT structure before integration.
issmatches your OpenID config issuersubcontains unique user identifieraudcontains your Alchemy-provided audience IDnonceortknoncecontainstoHex(sha256(targetPublicKey))without0x- JWT is signed with RS256 algorithm
- Verify your
.well-known/openid-configurationendpoint is accessible - Test JWKS endpoint returns valid public keys
- Validate JWT signature verification works
- Test complete authentication flow with sample users
Once your users have been authenticated, start sending transactions.
Start sponsoring gas fees for transactions via the Gas Manager.