0

Custom Authentication

awesome-llm-appsauthentication

Setting up OAuth with any identity provider (GitHub, Okta, Azure AD, Google, etc.).

Sign in to save downloads to your library and vote.

Preview

Custom Authentication

Setting up OAuth with any identity provider (GitHub, Okta, Azure AD, Google, etc.).


Quick Start

import { MCPServer, oauthCustomProvider, object } from "mcp-use/server";
import { createRemoteJWKSet, jwtVerify } from "jose";

const JWKS = createRemoteJWKSet(
  new URL("https://login.example.com/.well-known/jwks.json"),
);

const server = new MCPServer({
  name: "my-server",
  version: "1.0.0",
  oauth: oauthCustomProvider({
    issuer: "https://login.example.com",
    jwksUrl: "https://login.example.com/.well-known/jwks.json",
    authEndpoint: "https://login.example.com/oauth2/authorize",
    tokenEndpoint: "https://login.example.com/oauth2/token",
    verifyToken: async (token) => {
      const result = await jwtVerify(token, JWKS, {
        issuer: "https://login.example.com",
      });
      return result;
    },
  }),
});

server.tool(
  { name: "whoami", description: "Get authenticated user info" },
  async (_args, ctx) =>
    object({
      userId: ctx.auth.user.userId,
      email: ctx.auth.user.email,
    }),
);

server.listen();

Configuration Options

oauth: oauthCustomProvider({
  issuer: "https://login.example.com",              // required
  jwksUrl: "https://login.example.com/.well-known/jwks.json",  // required
  authEndpoint: "https://login.example.com/authorize",          // required
  tokenEndpoint: "https://login.example.com/token",             // required
  verifyToken: async (token) => { ... },             // required
  getUserInfo: (payload) => ({ ... }),                // optional
  scopesSupported: ["openid", "profile", "email"],   // optional
  grantTypesSupported: ["authorization_code", "refresh_token"], // optional
})
OptionTypeRequiredDescription
issuerstringYesOAuth issuer URL
jwksUrlstringYesJWKS endpoint for key discovery
authEndpointstringYesAuthorization endpoint
tokenEndpointstringYesToken endpoint
verifyToken(token: string) => Promise<{ payload }>YesCustom JWT verification function
getUserInfo(payload) => UserInfoNoCustom user info extraction
scopesSupportedstring[]NoDefaults to ["openid", "profile", "email"]
grantTypesSupportedstring[]NoDefaults to ["authorization_code", "refresh_token"]

Token Verification

You must provide a verifyToken function that validates the JWT and returns { payload }:

import { createRemoteJWKSet, jwtVerify } from "jose";

const JWKS = createRemoteJWKSet(
  new URL("https://login.example.com/.well-known/jwks.json"),
);

verifyToken: async (token) => {
  const result = await jwtVerify(token, JWKS, {
    issuer: "https://login.example.com",
    audience: "my-api", // if your provider requires audience validation
  });
  return result;
};

The jose library is already a dependency of mcp-use, so no additional install is needed.


Custom User Info Extraction

Without getUserInfo, the provider extracts standard OIDC claims automatically:

FieldExtracted From
userIdsub, user_id, or id
emailemail
namename
usernameusername or preferred_username
nicknamenickname
picturepicture or avatar_url
rolesroles (if array)
permissionspermissions (if array)
scopesParsed from scope string

Override this if your provider uses non-standard claim names:

getUserInfo: (payload) => ({
  userId: payload.user_id as string,
  email: payload.mail as string,
  name: payload.display_name as string,
  roles: (payload.groups as string[]) || [],
});

Provider Examples

GitHub (via GitHub Apps)

oauth: oauthCustomProvider({
  issuer: "https://github.com",
  jwksUrl: "https://token.actions.githubusercontent.com/.well-known/jwks",
  authEndpoint: "https://github.com/login/oauth/authorize",
  tokenEndpoint: "https://github.com/login/oauth/access_token",
  verifyToken: async (token) => {
    // GitHub tokens may need introspection rather than local JWT verification
    const res = await fetch("https://api.github.com/user", {
      headers: { Authorization: `Bearer ${token}` },
    });
    if (!res.ok) throw new Error("Invalid token");
    const user = await res.json();
    return { payload: user };
  },
  getUserInfo: (payload) => ({
    userId: String(payload.id),
    email: payload.email as string,
    name: payload.name as string,
    username: payload.login as string,
    picture: payload.avatar_url as string,
  }),
});

Okta

import { createRemoteJWKSet, jwtVerify } from "jose";

const OKTA_DOMAIN = process.env.OKTA_DOMAIN; // e.g., "dev-123456.okta.com"
const JWKS = createRemoteJWKSet(
  new URL(`https://${OKTA_DOMAIN}/oauth2/default/v1/keys`),
);

oauth: oauthCustomProvider({
  issuer: `https://${OKTA_DOMAIN}/oauth2/default`,
  jwksUrl: `https://${OKTA_DOMAIN}/oauth2/default/v1/keys`,
  authEndpoint: `https://${OKTA_DOMAIN}/oauth2/default/v1/authorize`,
  tokenEndpoint: `https://${OKTA_DOMAIN}/oauth2/default/v1/token`,
  verifyToken: async (token) =>
    jwtVerify(token, JWKS, {
      issuer: `https://${OKTA_DOMAIN}/oauth2/default`,
    }),
});

Azure AD

import { createRemoteJWKSet, jwtVerify } from "jose";

const TENANT_ID = process.env.AZURE_TENANT_ID;
const JWKS = createRemoteJWKSet(
  new URL(`https://login.microsoftonline.com/${TENANT_ID}/discovery/v2.0/keys`),
);

oauth: oauthCustomProvider({
  issuer: `https://login.microsoftonline.com/${TENANT_ID}/v2.0`,
  jwksUrl: `https://login.microsoftonline.com/${TENANT_ID}/discovery/v2.0/keys`,
  authEndpoint: `https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/authorize`,
  tokenEndpoint: `https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token`,
  verifyToken: async (token) =>
    jwtVerify(token, JWKS, {
      issuer: `https://login.microsoftonline.com/${TENANT_ID}/v2.0`,
    }),
  getUserInfo: (payload) => ({
    userId: payload.oid as string,
    email: payload.preferred_username as string,
    name: payload.name as string,
    roles: (payload.roles as string[]) || [],
  }),
});

Next Steps

Ingestion metadata

Source catalog
awesome-llm-apps
File path
generative_ui_agents/ai-mcp-app-builder/apps/mcp-use-server/.agent/skills/mcp-apps-builder/references/authentication/custom.md
Last refreshed
10/24/2026, 3:00:14 AM (5h ago)
Refresh schedule
Daily · 03:00 UTC
Dedupe status
Unique · deduped by (source, url)