mirror of
https://github.com/better-auth/better-auth.git
synced 2026-05-24 08:01:56 -05:00
test(sso): add tests for authorizationEndpoint hydration and discovery logic
This commit is contained in:
@@ -254,6 +254,88 @@ describe("SSO", async () => {
|
||||
expect(callbackURL).toContain("/dashboard");
|
||||
});
|
||||
|
||||
it("should hydrate authorizationEndpoint via discovery when missing from stored config", async () => {
|
||||
const { headers } = await signInWithTestUser();
|
||||
|
||||
// Register a provider with skipDiscovery, providing tokenEndpoint +
|
||||
// jwksEndpoint but deliberately omitting authorizationEndpoint.
|
||||
// This simulates a legacy provider stored without the authorization URL.
|
||||
await auth.api.registerSSOProvider({
|
||||
body: {
|
||||
issuer: server.issuer.url!,
|
||||
domain: "no-auth-endpoint.com",
|
||||
providerId: "no-auth-endpoint",
|
||||
oidcConfig: {
|
||||
clientId: "test",
|
||||
clientSecret: "test",
|
||||
skipDiscovery: true,
|
||||
tokenEndpoint: `${server.issuer.url}/token`,
|
||||
jwksEndpoint: `${server.issuer.url}/jwks`,
|
||||
discoveryEndpoint: `${server.issuer.url}/.well-known/openid-configuration`,
|
||||
mapping: {
|
||||
id: "sub",
|
||||
email: "email",
|
||||
emailVerified: "email_verified",
|
||||
name: "name",
|
||||
image: "picture",
|
||||
},
|
||||
},
|
||||
},
|
||||
headers,
|
||||
});
|
||||
|
||||
// Use a unique identity so the callback doesn't collide with the
|
||||
// "sso-user@localhost:8000.com" account already linked to "test" provider.
|
||||
const originalUserinfoListeners =
|
||||
server.service.listeners("beforeUserinfo");
|
||||
const originalTokenListeners =
|
||||
server.service.listeners("beforeTokenSigning");
|
||||
server.service.removeAllListeners("beforeUserinfo");
|
||||
server.service.removeAllListeners("beforeTokenSigning");
|
||||
server.service.on("beforeUserinfo", (userInfoResponse: any) => {
|
||||
userInfoResponse.body = {
|
||||
email: "no-auth-endpoint-user@no-auth-endpoint.com",
|
||||
name: "No Auth Endpoint User",
|
||||
sub: "no-auth-endpoint-user",
|
||||
email_verified: true,
|
||||
};
|
||||
userInfoResponse.statusCode = 200;
|
||||
});
|
||||
server.service.on("beforeTokenSigning", (token: any) => {
|
||||
token.payload.email = "no-auth-endpoint-user@no-auth-endpoint.com";
|
||||
token.payload.email_verified = true;
|
||||
token.payload.name = "No Auth Endpoint User";
|
||||
token.payload.sub = "no-auth-endpoint-user";
|
||||
});
|
||||
|
||||
try {
|
||||
const signInHeaders = new Headers();
|
||||
const res = await authClient.signIn.sso({
|
||||
providerId: "no-auth-endpoint",
|
||||
callbackURL: "/dashboard",
|
||||
fetchOptions: {
|
||||
throw: true,
|
||||
onSuccess: cookieSetter(signInHeaders),
|
||||
},
|
||||
});
|
||||
|
||||
// Discovery should have hydrated authorizationEndpoint — no error
|
||||
expect(res.url).toContain("http://localhost:8080/authorize");
|
||||
|
||||
const { callbackURL } = await simulateOAuthFlow(res.url, signInHeaders);
|
||||
expect(callbackURL).toContain("/dashboard");
|
||||
} finally {
|
||||
server.service.removeAllListeners("beforeUserinfo");
|
||||
server.service.removeAllListeners("beforeTokenSigning");
|
||||
for (const listener of originalUserinfoListeners) {
|
||||
server.service.on("beforeUserinfo", listener as any);
|
||||
}
|
||||
for (const listener of originalTokenListeners) {
|
||||
server.service.on("beforeTokenSigning", listener as any);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("should normalize email to lowercase in OIDC authentication", async () => {
|
||||
const { headers } = await signInWithTestUser();
|
||||
|
||||
|
||||
@@ -629,13 +629,23 @@ describe("OIDC Discovery", () => {
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false if both tokenEndpoint and jwksEndpoint are present", () => {
|
||||
it("should return false if tokenEndpoint, jwksEndpoint and authorizationEndpoint are all present", () => {
|
||||
expect(
|
||||
needsRuntimeDiscovery({
|
||||
tokenEndpoint: "https://idp.example.com/oauth2/token",
|
||||
jwksEndpoint: "https://idp.example.com/.well-known/jwks.json",
|
||||
authorizationEndpoint: "https://idp.example.com/oauth2/authorize",
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("should return true if authorizationEndpoint is missing", () => {
|
||||
expect(
|
||||
needsRuntimeDiscovery({
|
||||
tokenEndpoint: "https://idp.example.com/oauth2/token",
|
||||
jwksEndpoint: "https://idp.example.com/.well-known/jwks.json",
|
||||
}),
|
||||
).toBe(false);
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1176,6 +1186,7 @@ describe("ensureRuntimeDiscovery", () => {
|
||||
it("returns config unchanged when discovery is not needed", async () => {
|
||||
const completeConfig = {
|
||||
...baseConfig,
|
||||
authorizationEndpoint: `${issuer}/oauth2/authorize`,
|
||||
tokenEndpoint: `${issuer}/oauth2/token`,
|
||||
jwksEndpoint: `${issuer}/.well-known/jwks.json`,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user