Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
bilalmk avatar

Configuring Better Auth

  • 16 installs
  • 1 repo stars
  • Updated January 27, 2026
  • bilalmk/todo_correct

configuring-better-auth is a skill for implementing OAuth 2.1/OIDC single sign-on with Better Auth as an auth server or SSO client using PKCE and JWKS.

About

configuring-better-auth is a skill for implementing OAuth 2.1 / OIDC authentication with Better Auth, either as a centralized auth server (SSO provider) or as an SSO client in Next.js apps. It configures PKCE flows, registers OAuth clients, exchanges tokens, and manages tokens with JWKS verification and httpOnly cookies. A developer uses it to set up single sign-on across multiple apps, optionally with the Better Auth MCP for guided setup. It is not for simple session-only auth without OAuth/OIDC.

  • Implements OAuth 2.1 / OIDC auth with Better Auth as server or SSO client
  • Covers PKCE flows, JWKS token verification, and httpOnly cookies
  • Uses the Better Auth MCP for guided configuration

Configuring Better Auth by the numbers

  • 16 all-time installs (skills.sh)
  • Ranked #1,612 of 2,203 Security skills by installs in the Skillselion catalog
  • Data as of Jul 28, 2026 (Skillselion catalog sync)
At a glance

configuring-better-auth capabilities & compatibility

free (open-source libraries)

Capabilities
oauth setup · oidc provider · sso integration · jwks verification
Use cases
security audit · api development
Pricing
Free
From the docs

What configuring-better-auth says it does

Implement OAuth 2.1 / OIDC authentication using Better Auth with MCP assistance.
SKILL.md
Better Auth provides an MCP server powered by Chonkie for guided configuration:
SKILL.md
// Store verifier in cookie
SKILL.md
npx skills add https://github.com/bilalmk/todo_correct --skill configuring-better-auth

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs16
repo stars1
Last updatedJanuary 27, 2026
Repositorybilalmk/todo_correct

What it does

Set up OAuth 2.1/OIDC single sign-on with Better Auth as a central auth server or as SSO clients using PKCE and JWKS.

Who is it for?

Standing up OAuth/OIDC SSO with Better Auth across multiple apps

Skip if: Simple session-only auth without OAuth/OIDC requirements

When should I use this skill?

Setting up a centralized auth server, implementing SSO clients, or configuring PKCE flows with Better Auth

What you get

A Better Auth OIDC server and SSO clients with PKCE flows and JWKS-verified tokens.

  • Better Auth OIDC auth server
  • SSO client integration
  • PKCE auth flow and token exchange

By the numbers

  • Session config: 7-day expiry, 1-day update age
  • PKCE with S256 code challenge method

Files

SKILL.mdMarkdownGitHub ↗

Better Auth OAuth/OIDC

Implement centralized authentication with Better Auth - either as an auth server or SSO client.

MCP Server Setup

Better Auth provides an MCP server powered by Chonkie for guided configuration:

claude mcp add --transport http better-auth https://mcp.chonkie.ai/better-auth/better-auth-builder/mcp

Or in settings.json:

{
  "mcpServers": {
    "better-auth": {
      "type": "http",
      "url": "https://mcp.chonkie.ai/better-auth/better-auth-builder/mcp"
    }
  }
}

When to Use the MCP

TaskUse MCP?
Initial Better Auth setupYes - guided configuration
Adding OIDC provider pluginYes - generates correct config
Troubleshooting auth issuesYes - can analyze setup
Understanding auth flowYes - explains concepts
Writing custom middlewareNo - use patterns below

---

Architecture Overview

┌─────────────────┐
│ Better Auth SSO │ ← Central auth server (auth-server-setup.md)
│  (Auth Server)  │
└────────┬────────┘
         │
    ┌────┴────┐
    ▼         ▼
┌───────┐  ┌───────┐
│ App 1 │  │ App 2 │ ← SSO clients (sso-client-integration.md)
└───────┘  └───────┘

---

Quick Start: Auth Server Setup

npm install better-auth @better-auth/oidc-provider drizzle-orm

Core Configuration

// src/lib/auth.ts
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { oidcProvider } from "better-auth/plugins/oidc-provider";

export const auth = betterAuth({
  database: drizzleAdapter(db, { provider: "pg", schema }),
  emailAndPassword: { enabled: true },
  session: {
    expiresIn: 60 * 60 * 24 * 7, // 7 days
    updateAge: 60 * 60 * 24,     // 1 day
  },
  plugins: [
    oidcProvider({
      loginPage: "/sign-in",
      consentPage: "/consent",
      // PKCE for public clients (recommended)
      requirePKCE: true,
    }),
  ],
});

Register OAuth Clients

// Register SSO client
await auth.api.createOAuthClient({
  name: "My App",
  redirectUris: ["http://localhost:3000/api/auth/callback"],
  type: "public", // Use 'public' for PKCE
});

See references/auth-server-setup.md for complete setup with JWKS, email verification, and admin dashboard.

---

Quick Start: SSO Client Integration

npm install jose

Environment Variables

NEXT_PUBLIC_SSO_URL=http://localhost:3001
NEXT_PUBLIC_SSO_CLIENT_ID=your-client-id

PKCE Auth Flow

// lib/auth-client.ts
import { generateCodeVerifier, generateCodeChallenge } from "./pkce";

export async function startLogin() {
  const verifier = generateCodeVerifier();
  const challenge = await generateCodeChallenge(verifier);

  // Store verifier in cookie
  document.cookie = `pkce_verifier=${verifier}; path=/; SameSite=Lax`;

  const params = new URLSearchParams({
    client_id: process.env.NEXT_PUBLIC_SSO_CLIENT_ID!,
    redirect_uri: `${window.location.origin}/api/auth/callback`,
    response_type: "code",
    scope: "openid profile email",
    code_challenge: challenge,
    code_challenge_method: "S256",
  });

  window.location.href = `${SSO_URL}/oauth2/authorize?${params}`;
}

Token Exchange (API Route)

// app/api/auth/callback/route.ts
export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const code = searchParams.get("code");
  const verifier = cookies().get("pkce_verifier")?.value;

  const response = await fetch(`${SSO_URL}/oauth2/token`, {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: new URLSearchParams({
      grant_type: "authorization_code",
      client_id: process.env.NEXT_PUBLIC_SSO_CLIENT_ID!,
      code: code!,
      redirect_uri: `${process.env.NEXT_PUBLIC_APP_URL}/api/auth/callback`,
      code_verifier: verifier!,
    }),
  });

  const tokens = await response.json();

  // Set httpOnly cookies
  const res = NextResponse.redirect("/dashboard");
  res.cookies.set("access_token", tokens.access_token, { httpOnly: true });
  res.cookies.set("refresh_token", tokens.refresh_token, { httpOnly: true });
  return res;
}

See references/sso-client-integration.md for JWKS verification, token refresh, and global logout.

---

PKCE Utilities

// lib/pkce.ts
export function generateCodeVerifier(): string {
  const array = new Uint8Array(32);
  crypto.getRandomValues(array);
  return base64UrlEncode(array);
}

export async function generateCodeChallenge(verifier: string): Promise<string> {
  const encoder = new TextEncoder();
  const data = encoder.encode(verifier);
  const hash = await crypto.subtle.digest("SHA-256", data);
  return base64UrlEncode(new Uint8Array(hash));
}

function base64UrlEncode(buffer: Uint8Array): string {
  return btoa(String.fromCharCode(...buffer))
    .replace(/\+/g, "-")
    .replace(/\//g, "_")
    .replace(/=+$/, "");
}

---

Key Patterns

1. Token Storage

  • Store tokens in httpOnly cookies (not localStorage)
  • Use SameSite=Lax for CSRF protection

2. Token Refresh

async function refreshTokens() {
  const response = await fetch(`${SSO_URL}/oauth2/token`, {
    method: "POST",
    body: new URLSearchParams({
      grant_type: "refresh_token",
      client_id: process.env.NEXT_PUBLIC_SSO_CLIENT_ID!,
      refresh_token: currentRefreshToken,
    }),
  });
  return response.json();
}

3. JWKS Verification

import { createRemoteJWKSet, jwtVerify } from "jose";

const JWKS = createRemoteJWKSet(
  new URL(`${SSO_URL}/.well-known/jwks.json`)
);

export async function verifyAccessToken(token: string) {
  const { payload } = await jwtVerify(token, JWKS, {
    issuer: SSO_URL,
    audience: process.env.NEXT_PUBLIC_SSO_CLIENT_ID,
  });
  return payload;
}

4. Global Logout

// Logout from all apps
const logoutUrl = new URL(`${SSO_URL}/oauth2/logout`);
logoutUrl.searchParams.set("post_logout_redirect_uri", window.location.origin);
window.location.href = logoutUrl.toString();

---

Common Pitfalls

IssueSolution
PKCE verifier lost after redirectStore in httpOnly cookie before redirect
Token in localStorageUse httpOnly cookies instead
JWKS fetch failsCheck CORS on auth server
Consent screen loopsEnsure consent page saves decision

---

Verification

Run: python3 scripts/verify.py

Expected: ✓ configuring-better-auth skill ready

If Verification Fails

1. Check: references/ folder has both setup files 2. Stop and report if still failing

References

  • references/auth-server-setup.md - Complete auth server with OIDC provider
  • references/sso-client-integration.md - Full SSO client implementation

Related skills

FAQ

Does it provide guided setup?

Yes. Better Auth provides an MCP server powered by Chonkie for guided configuration, useful for initial setup and adding the OIDC provider plugin.

How are tokens stored on the client?

Access and refresh tokens are set as httpOnly cookies after the token exchange.

Securityappsecsecrets

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.