Skip to main content

Authentication

Crossmint SDK provides two authentication clients optimized for different environments: client-side and server-side. Both use JWT-based sessions with refresh tokens for secure, persistent authentication.

Client-Side Authentication

The CrossmintAuthClient is designed for browser and client-side environments, handling authentication flows with automatic token management.

Initialization

import { CrossmintAuth } from "@crossmint/client-sdk-auth";
import { createCrossmint } from "@crossmint/common-sdk-base";

const crossmint = createCrossmint({
  apiKey: "your-client-api-key"
});

const auth = CrossmintAuth.from(crossmint, {
  callbacks: {
    onTokenRefresh: (authMaterial) => {
      console.log("Token refreshed", authMaterial);
    },
    onLogout: () => {
      console.log("User logged out");
    }
  },
  logoutRoute: "/api/auth/logout" // Optional custom logout endpoint
});

Authentication Methods

The client supports multiple authentication flows:

Email OTP

// Send OTP to email
const { emailId } = await auth.sendEmailOtp("[email protected]");

// Verify OTP
const oneTimeSecret = await auth.confirmEmailOtp(
  "[email protected]",
  emailId,
  "123456"
);

// Exchange for session
await auth.handleRefreshAuthMaterial(oneTimeSecret);

OAuth Providers

// Get OAuth URL
const oauthUrl = await auth.getOAuthUrl("google");

// Redirect user to oauthUrl
window.location.href = oauthUrl;

// After redirect, exchange code for session
const params = new URLSearchParams(window.location.search);
const oneTimeSecret = params.get("ots");
await auth.handleRefreshAuthMaterial(oneTimeSecret);
OAuth providers include: google, twitter, discord, facebook, and more. Ensure the provider is enabled in your Crossmint Console.

Smart Wallet Authentication

// Request signature challenge
const { message } = await auth.signInWithSmartWallet(
  walletAddress,
  "evm" // or "solana"
);

// Sign message with wallet
const signature = await wallet.signMessage(message);

// Authenticate
const { oneTimeSecret } = await auth.authenticateSmartWallet(
  walletAddress,
  "evm",
  signature
);

await auth.handleRefreshAuthMaterial(oneTimeSecret);

Farcaster

import { useSignIn } from "@farcaster/auth-kit";

const farcasterData = useSignIn();
const oneTimeSecret = await auth.signInWithFarcaster(farcasterData);

await auth.handleRefreshAuthMaterial(oneTimeSecret);

Session Management

The client automatically refreshes JWT tokens before expiration and stores them in browser cookies/localStorage.
// Get current user
const user = await auth.getUser();
console.log(user.id, user.email);

// Logout
await auth.logout();

Token Storage

By default, authentication material is stored in cookies:
  • jwt - Session token (expires after 1 hour)
  • refreshToken - Long-lived refresh token (expires after 30 days)
You can customize storage with a custom StorageProvider:
const auth = CrossmintAuth.from(crossmint, {
  storageProvider: {
    get: async (key) => { /* custom get */ },
    set: async (key, value, expiresAt) => { /* custom set */ },
    remove: async (key) => { /* custom remove */ }
  }
});

Server-Side Authentication

The CrossmintAuthServer is designed for Node.js server environments, providing session validation and token refresh capabilities.

Initialization

import { CrossmintAuthServer } from "@crossmint/server-sdk-auth";
import { createCrossmint } from "@crossmint/common-sdk-base";

const crossmint = createCrossmint({
  apiKey: "your-server-api-key"
});

const authServer = CrossmintAuthServer.from(crossmint, {
  cookieOptions: {
    secure: true,
    httpOnly: true,
    sameSite: "strict"
  }
});

Session Validation

import { NextRequest, NextResponse } from "next/server";

export async function GET(request: NextRequest) {
  try {
    const session = await authServer.getSession(
      request,
      NextResponse.next()
    );
    
    return NextResponse.json({
      userId: session.userId,
      authenticated: true
    });
  } catch (error) {
    return NextResponse.json(
      { error: "Unauthorized" },
      { status: 401 }
    );
  }
}

JWT Verification

Verify and decode JWT tokens:
try {
  const decoded = await authServer.verifyCrossmintJwt(token);
  console.log("User ID:", decoded.sub);
  console.log("Expires:", decoded.exp);
} catch (error) {
  console.error("Invalid JWT");
}

Custom Refresh Route

Implement a custom refresh endpoint:
export async function POST(request: NextRequest) {
  const response = NextResponse.next();
  
  try {
    const refreshedResponse = await authServer.handleCustomRefresh(
      request,
      response
    );
    
    return refreshedResponse;
  } catch (error) {
    return NextResponse.json(
      { error: "Failed to refresh session" },
      { status: 401 }
    );
  }
}

Logout

export async function POST(request: NextRequest) {
  const response = NextResponse.next();
  const logoutResponse = await authServer.logout(request, response);
  
  return logoutResponse;
}

Authentication Flow

Best Practices

Use Server SDK for Protected Routes

Validate sessions on your backend using CrossmintAuthServer to prevent token tampering.

Handle Token Refresh Automatically

The client SDK automatically refreshes tokens before expiration. Listen to onTokenRefresh callbacks for updates.

Secure Your Cookies

Use httpOnly, secure, and sameSite cookie options in production to prevent XSS attacks.

Implement Custom Logout Route

Create a server-side logout endpoint to properly clear cookies and invalidate refresh tokens.

Error Handling

import { CrossmintAuthenticationError } from "@crossmint/common-sdk-auth";

try {
  await auth.confirmEmailOtp(email, emailId, otp);
} catch (error) {
  if (error instanceof CrossmintAuthenticationError) {
    console.error("Authentication failed:", error.message);
  }
}

Next Steps

Create Wallets

Learn how to create and manage embedded wallets for authenticated users

Configure Signers

Understand different signer types for wallet transactions

Build docs developers (and LLMs) love