Skip to content
Alchemy Logo

Bring Your Own Authentication

Integrate your existing authentication provider and add smart wallet functionality to your app without changing your users' login experience. We support 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 the iss claim in your JWTs)
  • jwks_uri: Endpoint URL where Alchemy can retrieve the JWT public key for verification
  • id_token_signing_alg_values_supported: Must include "RS256" algorithm

JWT Header Requirements

Your JWT header must include:

FieldDescriptionExample
algAlgorithm used to sign the JWT"RS256"
typToken type"JWT"
kidKey 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:

ClaimDescriptionExample
issIssuer - your auth provider's API domain"https://auth.example.com"
subSubject - unique user identifier"user123" or "550e8400-e29b-41d4-a716-446655440000"
audAudience - client ID issued by Alchemy"your-alchemy-audience-id"
nonceTarget public key hash (see below)"a1b2c3d4..."

Important: The nonce claim must be toHex(sha256(targetPublicKey)) without the leading 0x.

You can generate the targetPublicKey from the Alchemy Signer 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 your Alchemy-provided audience ID. You can obtain the audience claim from your Smart Wallet settings in the Alchemy Dashboard.

Audience Claim

npm install @account-kit/signer @account-kit/react

Before 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:

  1. User Authentication: User logs into your existing auth system
  2. JWT Generation: Your backend generates a JWT with required claims
  3. Submit to Alchemy: Frontend submits JWT to Alchemy's auth endpoint
  4. Verification: Alchemy verifies JWT using your JWKS endpoint
  5. 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 ready

Use jwt.io to decode and validate your JWT structure before integration.

  • iss matches your OpenID config issuer
  • sub contains unique user identifier
  • aud contains your Alchemy-provided audience ID
  • nonce or tknonce contains toHex(sha256(targetPublicKey)) without 0x
  • JWT is signed with RS256 algorithm

  1. Verify your .well-known/openid-configuration endpoint is accessible
  2. Test JWKS endpoint returns valid public keys
  3. Validate JWT signature verification works
  4. Test complete authentication flow with sample users

Once your users have been authenticated, you can start sending transactions.

Start sponsoring gas fees for transactions via the Gas Manager.

Was this page helpful?