Skip to main content
Connect Better Auth to authenticate end users with your Char agent. Configure Better Auth as an OIDC provider and set up Char for token validation.

Prerequisites

SDK References

Configuration Steps

1

Install Better Auth

Install the Better Auth package in your application. See the installation guide for details.
npm install better-auth
Configure your environment variables:
BETTER_AUTH_SECRET=your-32-character-secret-minimum
BETTER_AUTH_URL=https://auth.yourapp.com
2

Configure OIDC Provider and JWT Plugins

Set up Better Auth as an OIDC provider with JWT support for JWKS-based token validation:
// auth.ts
import { betterAuth } from "better-auth";
import { oidcProvider } from "better-auth/plugins";
import { jwt } from "better-auth/plugins";

export const auth = betterAuth({
  // Disable default /token endpoint (OIDC uses /oauth2/token)
  disabledPaths: ["/token"],
  plugins: [
    jwt({
      jwks: {
        // Key rotation settings
        rotationInterval: 60 * 60 * 24 * 30, // 30 days
        gracePeriod: 60 * 60 * 24 * 30,      // 30 days
      },
    }),
    oidcProvider({
      useJWTPlugin: true, // Use asymmetric signing with JWKS
      loginPage: "/sign-in",
      consentPage: "/consent",
      metadata: {
        issuer: "https://auth.yourapp.com",
      },
    }),
  ],
});
3

Configure Your Application as a Client

Register your application as a trusted OIDC client:
oidcProvider({
  useJWTPlugin: true,
  loginPage: "/sign-in",
  trustedClients: [
    {
      clientId: "your-app-client-id",
      clientSecret: "your-client-secret",
      redirectUrls: ["https://yourapp.com/callback"],
      skipConsent: true, // Skip consent for first-party apps
    },
  ],
}),
4

Configure Char

In the Char Dashboard:
  1. Navigate to SettingsIntegration
  2. Under SSO Configuration, select Custom OIDC as the provider
  3. Enter your Issuer URL (your Better Auth base URL, e.g., https://auth.yourapp.com)
  4. Enter your Client ID (the clientId from your trusted client config)
  5. Click Test Connection to verify
  6. Click Save Changes

Configuration Reference

Char FieldBetter Auth ValueExample
Provider TypeCustom OIDCoidc
Issuer URLYour Better Auth base URLhttps://auth.yourapp.com
Client IDTrusted client IDyour-app-client-id
Better Auth exposes the JWKS endpoint at /api/auth/jwks by default. The discovery document is available at /.well-known/openid-configuration when using the OIDC Provider plugin.

Using Upstream Identity Providers

If you’re using Better Auth with social login (Google, GitHub, etc.) or enterprise SSO, Better Auth acts as your identity layer. Char validates Better Auth’s tokens, not the upstream provider’s tokens.

Understanding Auth Platforms vs Direct IDPs

Learn how auth platforms like Better Auth issue their own tokens after upstream OAuth flows

Token Requirements

Char validates Better Auth ID tokens with these requirements:
ClaimRequirement
issMust match your configured issuer URL
audMust include your configured Client ID
subRequired - used as the user identifier
expMust not be expired

Better Auth ID Token Claims

When using the JWT plugin with OIDC Provider, tokens include these claims based on requested scopes:
ScopeClaims Included
openidsub (user ID)
profilename, picture, given_name, family_name
emailemail, email_verified
You can add custom claims via the getAdditionalUserInfoClaim callback in the OIDC Provider configuration.

Example: Obtaining and Passing the Token

import { createAuthClient } from "better-auth/react";
import { useEffect, useRef } from "react";
import "@mcp-b/char/web-component";
import type { WebMCPAgentElement } from "@mcp-b/char/web-component";

const CLIENT_ID = "your-oidc-client-id";

const authClient = createAuthClient({
  baseURL: "https://auth.yourapp.com",
});

function App() {
  const { data: session } = authClient.useSession();
  const agentRef = useRef<WebMCPAgentElement>(null);

  useEffect(() => {
    if (session?.user && agentRef.current) {
      // Get the ID token from your auth flow
      // Better Auth stores session info - you'll need to
      // implement token retrieval based on your setup
      fetchIdToken().then((idToken) => {
        agentRef.current?.connect({ idToken, clientId: CLIENT_ID });
      });
    }
  }, [session]);

  return <char-agent ref={agentRef} />;
}

JWKS Endpoint

Better Auth with the JWT plugin exposes a JWKS endpoint for token verification:
EndpointURL
JWKShttps://auth.yourapp.com/api/auth/jwks
Discoveryhttps://auth.yourapp.com/.well-known/openid-configuration
The JWKS endpoint returns public keys used to verify token signatures:
{
  "keys": [
    {
      "kty": "OKP",
      "crv": "Ed25519",
      "x": "...",
      "kid": "key-id"
    }
  ]
}

Key Rotation

Better Auth supports automatic key rotation:
jwt({
  jwks: {
    rotationInterval: 60 * 60 * 24 * 30, // Rotate every 30 days
    gracePeriod: 60 * 60 * 24 * 30,      // Keep old keys valid for 30 days
  },
})
During the grace period, both old and new keys are valid, allowing clients to verify tokens signed by either key.

Troubleshooting

The token issuer doesn’t match your configured URL:
  • Verify the Issuer URL in Char matches your Better Auth metadata.issuer exactly
  • Ensure you’re using the full URL including https://
  • Check that BETTER_AUTH_URL environment variable is set correctly
The token’s aud claim doesn’t match your configured Client ID:
  • Ensure the Client ID matches your trustedClients configuration
  • Verify you’re using the ID token, not a session token
  • Check that the client is registered in the OIDC Provider plugin
Char couldn’t reach Better Auth’s JWKS endpoint:
  • Verify your Better Auth instance is publicly accessible
  • Check that the JWT plugin is enabled with useJWTPlugin: true
  • Ensure /api/auth/jwks endpoint is not blocked by middleware
  • Use Test Connection in the dashboard to verify
If tokens fail signature verification:
  • Ensure useJWTPlugin: true is set in the OIDC Provider config
  • Check that the JWT plugin is using the same keys for signing
  • If keys were recently rotated, wait for cache refresh or clear JWKS cache

Better Auth Features

Better Auth offers additional features that complement Char integration:
FeatureDescription
Multi-session SupportUsers can have multiple active sessions
Social LoginGoogle, GitHub, Discord, and 20+ providers
Two-Factor AuthTOTP and backup codes
OrganizationsMulti-tenant support with teams
Session ManagementRevoke sessions, track devices

Better Auth Documentation

Explore the full Better Auth documentation

Security Best Practices

  • Use asymmetric signing with the JWT plugin for production (useJWTPlugin: true)
  • Configure key rotation to limit the impact of key compromise
  • Use HTTPS for all endpoints in production
  • Set appropriate token expiration times
  • Register only trusted clients with skipConsent: true
  • Monitor auth logs for suspicious activity