ItalyPaleAleandGustavo Valverde 23041d94fd feat: add JWT client assertion OAuth2 support (next)
> This is a re-do of #9418 for the `next` branch, where #8836 was merged. As discussed via Slack, backwards compatibility did not need to be maintained.

This is based on RFC 7523

It allows configuring an OAuth2 provider with a `clientAssertionProvider` instead of a `clientSecret`, so omitting long-lived credentials.

This PR is currently not concerned with what providers support (or will support) client assertions. It is also not concerned with _how_ the assertion is obtained: could be a Kubernetes token, a token from a cloud platform, etc.

This PR refactors/extends #8836, which was limited to supporting assertions generated locally with a private key (which, while having broader support in the ecosystem, still involves long-lived secrets). Support for those assertions is available by passing `createPrivateKeyJwtClientAssertionProvider(opts)` to the `clientAssertionProvider` property.

This was implemented by #8836 and it's refactored here so it works in a more generic way.

With this PR, JWTs can be signed with a local assertion:

```ts
import { betterAuth } from "better-auth";
import { genericOAuth } from "better-auth/plugins/generic-oauth";
import { createPrivateKeyJwtClientAssertionProvider } from "better-auth/oauth2";

genericOAuth({
  config: [
    {
      providerId: "my-idp",
      discoveryUrl: "https://idp.example.com/.well-known/openid-configuration",
      clientId: process.env.IDP_CLIENT_ID!,
      // Replaces clientSecret
      clientAssertionProvider: createPrivateKeyJwtClientAssertionProvider({
        clientId: "your-client-id",
        tokenEndpoint: "https://idp.example.com/oauth/token",
        privateKeyJwk: { /* your JWK */ },
        kid: "my-key-1",
        algorithm: "RS256",
      }),
      pkce: true,
    },
  ],
});
```

For an application running on Vercel and authenticating with a generic OAuth2 provider (e.g. Pocket ID), you can now configure better-auth with:

```ts
import { getVercelOidcToken } from '@vercel/oidc'

genericOAuth({
  config: [
    {
      providerId: "my-idp",
      discoveryUrl: "https://idp.example.com/.well-known/openid-configuration",
      clientId: process.env.IDP_CLIENT_ID!,
      // Replaces clientSecret
      clientAssertionProvider: async (): Promise<string> => {
        return getVercelOidcToken()
      },
      pkce: true,
    },
  ],
});
```

You then just need to configure your application in the IdP to accept federation with these values:

- Issuer: `https://oidc.vercel.com/<vercel-team>`
- Audience: `https://vercel.com/<vercel-team>`
- Subject: `owner:<vercel-team>:project:<project-name>:environment:production`
2026-05-16 20:56:42 +01:00
2026-04-23 19:50:25 +00:00
2026-04-23 19:50:25 +00:00
2026-04-23 19:50:25 +00:00
2026-01-21 04:08:09 +00:00
2026-04-18 23:04:27 -07:00

Better Auth

Better Auth is a framework-agnostic authentication (and authorization) framework for TypeScript. It provides a comprehensive set of features out of the box and includes a plugin ecosystem that simplifies adding advanced functionalities with minimal code in a short amount of time. Whether you need 2FA, multi-tenant support, or other complex features, it lets you focus on building your actual application instead of reinventing the wheel.

Why Better Auth

Authentication in the TypeScript ecosystem is a half-solved problem. Other open-source libraries often require a lot of additional code for anything beyond basic authentication. Rather than just pushing third-party services as the solution, I believe we can do better as a community—hence, Better Auth.

Contribution

Better Auth is a free and open source project licensed under the MIT License. You are free to do whatever you want with it.

You could help continuing its development by:

Security

If you discover a security vulnerability within Better Auth, please send an e-mail to security@better-auth.com.

All reports will be promptly addressed, and you'll be credited accordingly.

S
Description
No description provided
Readme
261 MiB
Latest
2026-04-16 05:05:30 -05:00
Languages
TypeScript 99.4%
CSS 0.3%
MDX 0.2%