mirror of
https://github.com/better-auth/better-auth.git
synced 2026-08-01 10:50:40 -05:00
chore: fix jwt not working with different algs
This commit is contained in:
@@ -7,7 +7,7 @@ import type {
|
||||
import { type Jwk, schema } from "./schema";
|
||||
import { getJwksAdapter } from "./adapter";
|
||||
import { getJwtToken } from "./sign";
|
||||
import { exportJWK, generateKeyPair } from "jose";
|
||||
import { exportJWK, generateKeyPair, type JWK } from "jose";
|
||||
import {
|
||||
createAuthEndpoint,
|
||||
createAuthMiddleware,
|
||||
@@ -119,6 +119,26 @@ export interface JwtOptions {
|
||||
schema?: InferOptionSchema<typeof schema>;
|
||||
}
|
||||
|
||||
export async function generateExportedKeyPair(
|
||||
options?: JwtOptions,
|
||||
): Promise<{ publicWebKey: JWK; privateWebKey: JWK }> {
|
||||
const { alg, ...cfg } = options?.jwks?.keyPairConfig ?? {
|
||||
alg: "EdDSA",
|
||||
crv: "Ed25519",
|
||||
};
|
||||
const keyPairConfig = {
|
||||
...cfg,
|
||||
extractable: true,
|
||||
};
|
||||
|
||||
const { publicKey, privateKey } = await generateKeyPair(alg, keyPairConfig);
|
||||
|
||||
const publicWebKey = await exportJWK(publicKey);
|
||||
const privateWebKey = await exportJWK(privateKey);
|
||||
|
||||
return { publicWebKey, privateWebKey };
|
||||
}
|
||||
|
||||
export const jwt = (options?: JwtOptions) => {
|
||||
return {
|
||||
id: "jwt",
|
||||
@@ -221,8 +241,8 @@ export const jwt = (options?: JwtOptions) => {
|
||||
crv: "Ed25519",
|
||||
};
|
||||
const keyPairConfig = {
|
||||
extractable: true,
|
||||
...cfg,
|
||||
extractable: true,
|
||||
};
|
||||
|
||||
const { publicKey, privateKey } = await generateKeyPair(
|
||||
|
||||
@@ -2,7 +2,7 @@ import { describe, expect } from "vitest";
|
||||
import { getTestInstance } from "../../test-utils/test-instance";
|
||||
import { createAuthClient } from "../../client";
|
||||
import { jwtClient } from "./client";
|
||||
import { jwt } from "./index";
|
||||
import { generateExportedKeyPair, jwt, type JwtOptions } from "./index";
|
||||
import { importJWK, jwtVerify } from "jose";
|
||||
|
||||
type JWKOptions =
|
||||
@@ -228,18 +228,17 @@ describe("jwt", async (it) => {
|
||||
for (const algorithm of algorithmsToTest) {
|
||||
const expectedOutcome = algorithm.expectedOutcome;
|
||||
for (let disablePrivateKeyEncryption of [false, true]) {
|
||||
const jwtOptions: JwtOptions = {
|
||||
jwks: {
|
||||
keyPairConfig: {
|
||||
...algorithm.keyPairConfig,
|
||||
},
|
||||
disablePrivateKeyEncryption: disablePrivateKeyEncryption,
|
||||
},
|
||||
};
|
||||
try {
|
||||
const { auth, signInWithTestUser } = await getTestInstance({
|
||||
plugins: [
|
||||
jwt({
|
||||
jwks: {
|
||||
keyPairConfig: {
|
||||
...algorithm.keyPairConfig,
|
||||
},
|
||||
disablePrivateKeyEncryption: disablePrivateKeyEncryption,
|
||||
},
|
||||
}),
|
||||
],
|
||||
plugins: [jwt(jwtOptions)],
|
||||
logger: {
|
||||
level: "error",
|
||||
},
|
||||
@@ -269,6 +268,17 @@ describe("jwt", async (it) => {
|
||||
expect(jwks?.keys.at(0)?.n).toHaveLength(expectedOutcome.length);
|
||||
});
|
||||
|
||||
it(`${alg} algorithm${enc}: Endpoint "/token" can extract valid keys`, async () => {
|
||||
const { publicWebKey, privateWebKey } =
|
||||
await generateExportedKeyPair(jwtOptions);
|
||||
for (const key of [publicWebKey, privateWebKey]) {
|
||||
expect(key.kty).toBe(expectedOutcome.ec);
|
||||
if (key.x) expect(key.x).toHaveLength(expectedOutcome.length);
|
||||
if (key.y) expect(key.y).toHaveLength(expectedOutcome.length);
|
||||
if (key.n) expect(key.n).toHaveLength(expectedOutcome.length);
|
||||
}
|
||||
});
|
||||
|
||||
const client = createAuthClient({
|
||||
plugins: [jwtClient()],
|
||||
baseURL: "http://localhost:3000/api/auth",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { importJWK, exportJWK, generateKeyPair, SignJWT } from "jose";
|
||||
import { importJWK, SignJWT } from "jose";
|
||||
import type { GenericEndpointContext } from "../../types";
|
||||
import { BetterAuthError } from "../../error";
|
||||
import { symmetricDecrypt, symmetricEncrypt } from "../../crypto";
|
||||
import type { JwtOptions } from ".";
|
||||
import { generateExportedKeyPair, type JwtOptions } from ".";
|
||||
import type { Jwk } from "./schema";
|
||||
import { getJwksAdapter } from "./adapter";
|
||||
|
||||
@@ -17,16 +17,8 @@ export async function getJwtToken(
|
||||
!options?.jwks?.disablePrivateKeyEncryption;
|
||||
|
||||
if (key === undefined) {
|
||||
const { publicKey, privateKey } = await generateKeyPair(
|
||||
options?.jwks?.keyPairConfig?.alg ?? "EdDSA",
|
||||
options?.jwks?.keyPairConfig ?? {
|
||||
crv: "Ed25519",
|
||||
extractable: true,
|
||||
},
|
||||
);
|
||||
|
||||
const publicWebKey = await exportJWK(publicKey);
|
||||
const privateWebKey = await exportJWK(privateKey);
|
||||
const { publicWebKey, privateWebKey } =
|
||||
await generateExportedKeyPair(options);
|
||||
const stringifiedPrivateWebKey = JSON.stringify(privateWebKey);
|
||||
|
||||
let jwk: Partial<Jwk> = {
|
||||
|
||||
Reference in New Issue
Block a user