Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
DEPRECATED: Replaced by mcp-app-builder. Previously used to build ChatGPT apps with interactive React widgets via mcp-use.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/authentication/better-auth.md
1# Better Auth Authentication23Setting up a self-hosted OAuth 2.1 authorization server with Better Auth.45**Learn more:** [Better Auth OAuth Provider Plugin](https://better-auth.com/docs/plugins/oauth-provider) · [Standalone starter template](https://github.com/mcp-use/mcp-oauth-better-auth-template) · [Runnable example](https://github.com/mcp-use/mcp-use/tree/main/libraries/typescript/packages/mcp-use/examples/server/oauth/better-auth)67> Covers the `@better-auth/oauth-provider` plugin. The older Better Auth MCP plugin is deprecated — for legacy users, see the [mcp-use adapter](https://better-auth.com/docs/plugins/mcp#framework-adapters).89---1011## How It Works1213Unlike WorkOS, Auth0, or Supabase, Better Auth runs **inside** your MCP server — your server *is* the OAuth 2.1 authorization server. Better Auth handles the full OAuth flow (authorization, token issuance, JWKS); mcp-use only verifies the resulting JWTs.1415This means:16- No external auth service required17- You control the login and consent UX18- Requires a database (SQLite, Postgres, etc.)19- More setup than hosted providers2021---2223## Install2425```bash26npm install better-auth @better-auth/oauth-provider better-sqlite327```2829---3031## Setup3233### 1. Configure Better Auth (`auth.ts`)3435```typescript36import { betterAuth } from "better-auth";37import { jwt } from "better-auth/plugins";38import { oauthProvider } from "@better-auth/oauth-provider";39import Database from "better-sqlite3";4041export const auth = betterAuth({42authURL: "http://localhost:3000",43basePath: "/api/auth",44secret: process.env.BETTER_AUTH_SECRET!,4546database: new Database("./sqlite.db"),4748socialProviders: {49github: {50clientId: process.env.GITHUB_CLIENT_ID!,51clientSecret: process.env.GITHUB_CLIENT_SECRET!,52},53},5455plugins: [56jwt(), // Required: signs and verifies access tokens57oauthProvider({58loginPage: "/sign-in",59consentPage: "/consent",60allowDynamicClientRegistration: true,61allowUnauthenticatedClientRegistration: true,62// Must include your MCP endpoint as a valid audience63validAudiences: ["http://localhost:3000/mcp"],64// Expose user profile claims in access token JWTs65customAccessTokenClaims: async ({ user }) => ({66email: user?.email,67name: user?.name,68picture: user?.image,69}),70}),71],72});73```7475### 2. Generate and migrate the database7677```bash78npx auth@latest generate79npx auth@latest migrate80```8182### 3. Configure the MCP server (`server.ts`)8384You need three things beyond the standard `MCPServer` setup:851. Mount Better Auth routes (`/api/auth/**`)862. Mount OAuth discovery endpoints with CORS headers (required for browser clients)873. Mount login and consent pages8889```typescript90import { MCPServer, oauthBetterAuthProvider } from "mcp-use/server";91import { auth } from "./auth.js";92import {93oauthProviderAuthServerMetadata,94oauthProviderOpenIdConfigMetadata,95} from "@better-auth/oauth-provider";9697const server = new MCPServer({98name: "my-server",99version: "1.0.0",100oauth: oauthBetterAuthProvider({101authURL: "http://localhost:3000/api/auth",102}),103});104105// Mount Better Auth routes106server.app.on(["GET", "POST"], "/api/auth/**", (c) => auth.handler(c.req.raw));107108// OAuth discovery endpoints — CORS headers are required for browser clients (MCP Inspector)109const corsHeaders = {110"Access-Control-Allow-Origin": "*",111"Access-Control-Allow-Methods": "GET",112};113const authServerMetadataHandler = oauthProviderAuthServerMetadata(auth, { headers: corsHeaders });114server.app.get("/.well-known/oauth-authorization-server", (c) => authServerMetadataHandler(c.req.raw));115server.app.get("/.well-known/oauth-authorization-server/api/auth", (c) => authServerMetadataHandler(c.req.raw));116117const openIdConfigHandler = oauthProviderOpenIdConfigMetadata(auth, { headers: corsHeaders });118server.app.get("/.well-known/openid-configuration", (c) => openIdConfigHandler(c.req.raw));119server.app.get("/.well-known/openid-configuration/api/auth", (c) => openIdConfigHandler(c.req.raw));120121await server.listen(3000);122```123124### 4. Add login and consent pages125126Better Auth requires a `/sign-in` page and a `/consent` page mounted on the Hono app.127128- **Sign-in page:** POST to `/api/auth/sign-in/social` with the provider name and `callbackURL: '/api/auth/oauth2/authorize' + queryString` (preserve the OAuth query params).129- **Consent page:** POST to `/api/auth/oauth2/consent` with `{ accept: boolean, oauth_query: window.location.search.slice(1) }`.130- Both must use `credentials: 'include'` on fetch calls.131132See the [runnable example](https://github.com/mcp-use/mcp-use/tree/main/libraries/typescript/packages/mcp-use/examples/server/oauth/better-auth) for complete HTML/JS.133134---135136## Environment Variables137138```bash139# Better Auth secret (used for signing cookies and tokens)140BETTER_AUTH_SECRET=your-secret-change-in-production141142# Social provider credentials (GitHub shown — swap for any supported provider)143# Set callback URL in provider dashboard to: http://localhost:3000/api/auth/callback/<provider>144GITHUB_CLIENT_ID=your-github-client-id145GITHUB_CLIENT_SECRET=your-github-client-secret146```147148Better Auth supports many social providers (GitHub, Google, Discord, etc.). See [Better Auth social providers docs](https://www.better-auth.com/docs/concepts/oauth) for the full list.149150---151152## Configuration Options153154```typescript155oauthBetterAuthProvider({156authURL: "https://yourapp.com/api/auth", // Required: full URL including basePath157verifyJwt: process.env.NODE_ENV === "production", // default: true158scopesSupported: ["openid", "profile", "email", "offline_access"], // override advertised scopes159getUserInfo: (payload) => ({160userId: payload.sub as string,161email: payload.email as string,162name: payload.name as string,163roles: (payload.roles as string[]) || [],164permissions: (payload.permissions as string[]) || [],165}),166})167```168169| Option | Type | Default | Description |170|--------|------|---------|-------------|171| `authURL` | `string` | env var | Better Auth base URL including `/api/auth` path |172| `verifyJwt` | `boolean?` | `true` | Set `false` to skip JWT verification (**development only**) |173| `scopesSupported` | `string[]?` | `["openid", "profile", "email", "offline_access"]` | Override advertised scopes |174| `getUserInfo` | `function?` | built-in | Custom extraction of user info from JWT payload |175176---177178## Accessing user info in tools179180```typescript181server.tool(182{ name: "get-user-info", description: "Get information about the authenticated user" },183async (_args, ctx) =>184object({185userId: ctx.auth.user.userId,186email: ctx.auth.user.email,187name: ctx.auth.user.name,188scopes: ctx.auth.scopes,189permissions: ctx.auth.permissions,190})191);192```193194---195196## Common Mistakes197198- **Missing `validAudiences`** — Must include your MCP endpoint (e.g. `http://localhost:3000/mcp`) or JWT verification will fail with an audience mismatch.199- **Missing CORS headers on discovery endpoints** — Browser clients like MCP Inspector require `Access-Control-Allow-Origin: *` on `/.well-known/*` routes.200- **Skipping `jwt()` plugin** — Required for token signing; omitting it breaks token issuance.201- **Wrong `authURL`** — `oauthBetterAuthProvider({ authURL })` must include the full basePath (e.g. `/api/auth`), not just the host.202- **Missing `credentials: 'include'`** — Login and consent page fetch calls must include cookies or the session will be lost.203204---205206## Next Steps207208- **Auth overview** → [overview.md](overview.md)209- **WorkOS setup** → [workos.md](workos.md)210- **Supabase setup** → [supabase.md](supabase.md)211- **Keycloak setup** → [keycloak.md](keycloak.md)212- **Build tools** → [../server/tools.md](../server/tools.md)213