mirror of
https://github.com/better-auth/better-auth.git
synced 2026-10-19 11:24:57 -05:00
test(oauth): cover exchange-throw logging and guard against raw token leaks
This commit is contained in:
@@ -17,7 +17,11 @@ describe("callback", () => {
|
||||
validateAuthorizationCode: async () =>
|
||||
// Mirrors a provider (e.g. Slack) that answers with HTTP 200 but an
|
||||
// error in the response body instead of failing the HTTP request.
|
||||
getOAuth2Tokens({ ok: false, error: "invalid_code" }),
|
||||
getOAuth2Tokens({
|
||||
ok: false,
|
||||
error: "invalid_code",
|
||||
refresh_token: "sensitive-refresh-token",
|
||||
}),
|
||||
getUserInfo: async () => null,
|
||||
} satisfies OAuthProvider<Record<string, never>>;
|
||||
|
||||
@@ -70,6 +74,66 @@ describe("callback", () => {
|
||||
});
|
||||
// The raw token response must never be logged as-is.
|
||||
expect(JSON.stringify(noTokenCalls[0])).not.toContain('"raw"');
|
||||
expect(JSON.stringify(noTokenCalls[0])).not.toContain(
|
||||
"sensitive-refresh-token",
|
||||
);
|
||||
|
||||
errorSpy.mockRestore();
|
||||
});
|
||||
|
||||
it("logs the provider id when the authorization code exchange throws", async () => {
|
||||
const exchangeError = new Error("token endpoint unreachable");
|
||||
const provider = {
|
||||
id: "throwing-provider",
|
||||
name: "Throwing Provider",
|
||||
accountSubject: () => "subject",
|
||||
createAuthorizationURL: ({ state }) =>
|
||||
new URL(`https://idp.example.com/authorize?state=${state}`),
|
||||
validateAuthorizationCode: async () => {
|
||||
throw exchangeError;
|
||||
},
|
||||
getUserInfo: async () => null,
|
||||
} satisfies OAuthProvider<Record<string, never>>;
|
||||
|
||||
const { client, auth, cookieSetter } = await getTestInstance({
|
||||
plugins: [
|
||||
{
|
||||
id: "throwing-provider-plugin",
|
||||
init: (ctx) => ({
|
||||
context: {
|
||||
socialProviders: [provider, ...ctx.socialProviders],
|
||||
},
|
||||
}),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const ctx = await auth.$context;
|
||||
const errorSpy = vi.spyOn(ctx.logger, "error").mockImplementation(() => {});
|
||||
|
||||
const oAuthHeaders = new Headers();
|
||||
const signIn = await client.signIn.social(
|
||||
{
|
||||
provider: provider.id,
|
||||
callbackURL: "/dashboard",
|
||||
},
|
||||
{
|
||||
throw: true,
|
||||
onSuccess: cookieSetter(oAuthHeaders),
|
||||
},
|
||||
);
|
||||
const state = new URL(signIn.url!).searchParams.get("state");
|
||||
|
||||
await client.$fetch(`/callback/${provider.id}?code=test&state=${state}`, {
|
||||
method: "GET",
|
||||
headers: oAuthHeaders,
|
||||
onError() {},
|
||||
});
|
||||
|
||||
expect(errorSpy).toHaveBeenCalledWith(
|
||||
"Failed to exchange OAuth authorization code",
|
||||
{ providerId: provider.id, error: exchangeError },
|
||||
);
|
||||
|
||||
errorSpy.mockRestore();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user