add state param to oauth provider (#529)

This commit is contained in:
Jeff Escalante 2025-05-22 07:55:00 -04:00 • committed by GitHub
commit 0516f9898b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 39 additions and 0 deletions

View file

@ -366,6 +366,31 @@ describe("OAuth Authorization", () => {
expect(authorizationUrl.searchParams.has("scope")).toBe(false);
});
it("includes state parameter when provided", async () => {
const { authorizationUrl } = await startAuthorization(
"https://auth.example.com",
{
clientInformation: validClientInfo,
redirectUrl: "http://localhost:3000/callback",
state: "foobar",
}
);
expect(authorizationUrl.searchParams.get("state")).toBe("foobar");
});
it("excludes state parameter when not provided", async () => {
const { authorizationUrl } = await startAuthorization(
"https://auth.example.com",
{
clientInformation: validClientInfo,
redirectUrl: "http://localhost:3000/callback",
}
);
expect(authorizationUrl.searchParams.has("state")).toBe(false);
});
it("uses metadata authorization_endpoint when provided", async () => {
const { authorizationUrl } = await startAuthorization(
"https://auth.example.com",

View file

@ -21,6 +21,11 @@ export interface OAuthClientProvider {
*/
get clientMetadata(): OAuthClientMetadata;
/**
* Returns a OAuth2 state parameter.
*/
state?(): string | Promise<string>;
/**
* Loads information about this OAuth client, as registered already with the
* server, or returns `undefined` if the client is not registered with the
@ -162,10 +167,13 @@ export async function auth(
}
}
const state = provider.state ? await provider.state() : undefined;
// Start new authorization flow
const { authorizationUrl, codeVerifier } = await startAuthorization(authorizationServerUrl, {
metadata,
clientInformation,
state,
redirectUrl: provider.redirectUrl,
scope: scope || provider.clientMetadata.scope,
});
@ -301,11 +309,13 @@ export async function startAuthorization(
clientInformation,
redirectUrl,
scope,
state,
}: {
metadata?: OAuthMetadata;
clientInformation: OAuthClientInformation;
redirectUrl: string | URL;
scope?: string;
state?: string;
},
): Promise<{ authorizationUrl: URL; codeVerifier: string }> {
const responseType = "code";
@ -347,6 +357,10 @@ export async function startAuthorization(
);
authorizationUrl.searchParams.set("redirect_uri", String(redirectUrl));
if (state) {
authorizationUrl.searchParams.set("state", state);
}
if (scope) {
authorizationUrl.searchParams.set("scope", scope);
}