diff --git a/docs/oidc-client-ts.api.md b/docs/oidc-client-ts.api.md index 1077f33e6..ebbb47a02 100644 --- a/docs/oidc-client-ts.api.md +++ b/docs/oidc-client-ts.api.md @@ -265,7 +265,7 @@ export class OidcClient { // (undocumented) createSigninRequest({ state, request, request_uri, request_type, id_token_hint, login_hint, skipUserInfo, nonce, response_type, scope, redirect_uri, prompt, display, max_age, ui_locales, acr_values, resource, response_mode, extraQueryParams, extraTokenParams, }: CreateSigninRequestArgs): Promise; // (undocumented) - createSignoutRequest({ state, id_token_hint, request_type, post_logout_redirect_uri, extraQueryParams, }?: CreateSignoutRequestArgs): Promise; + createSignoutRequest({ state, id_token_hint, client_id, request_type, post_logout_redirect_uri, extraQueryParams, }?: CreateSignoutRequestArgs): Promise; // (undocumented) protected readonly _logger: Logger; // (undocumented) @@ -720,7 +720,7 @@ export type SignoutRedirectArgs = RedirectParams & ExtraSignoutRequestArgs; // @public (undocumented) export class SignoutRequest { - constructor({ url, state_data, id_token_hint, post_logout_redirect_uri, extraQueryParams, request_type, }: SignoutRequestArgs); + constructor({ url, state_data, id_token_hint, post_logout_redirect_uri, extraQueryParams, request_type, client_id, }: SignoutRequestArgs); // (undocumented) readonly state?: State; // (undocumented) @@ -729,6 +729,8 @@ export class SignoutRequest { // @public (undocumented) export interface SignoutRequestArgs { + // (undocumented) + client_id?: string; // (undocumented) extraQueryParams?: Record; // (undocumented) diff --git a/samples/Parcel/src/oidc-client/sample.js b/samples/Parcel/src/oidc-client/sample.js index e20c403f3..a63bf52a8 100644 --- a/samples/Parcel/src/oidc-client/sample.js +++ b/samples/Parcel/src/oidc-client/sample.js @@ -49,7 +49,7 @@ function signin() { var signinResponse; function processSigninResponse() { - client.processSigninResponse().then(function(response) { + client.processSigninResponse(window.location.href).then(function(response) { signinResponse = response; log("signin response", signinResponse); }).catch(function(err) { @@ -59,7 +59,7 @@ function processSigninResponse() { } function signout() { - client.createSignoutRequest({ state: { foo: 5 } }).then(function(req) { + client.createSignoutRequest({ state: { foo: 5 }, client_id: settings.client_id }).then(function(req) { log("signout request", req, "go signout"); if (followLinks()) { window.location = req.url; @@ -68,7 +68,7 @@ function signout() { } function processSignoutResponse() { - client.processSignoutResponse().then(function(response) { + client.processSignoutResponse(window.location.href).then(function(response) { signinResponse = null; log("signout response", response); }).catch(function(err) { diff --git a/src/OidcClient.test.ts b/src/OidcClient.test.ts index d79680444..04fed8610 100644 --- a/src/OidcClient.test.ts +++ b/src/OidcClient.test.ts @@ -563,6 +563,45 @@ describe("OidcClient", () => { expect(url).toContain("id_token_hint=baz"); }); + it("should pass params to SignoutRequest w/o id_token_hint and client_id", async () => { + // arrange + jest.spyOn(subject.metadataService, "getEndSessionEndpoint").mockImplementation(() => Promise.resolve("http://sts/signout")); + + // act + const request = await subject.createSignoutRequest({ + state: "foo", + post_logout_redirect_uri: "bar", + }); + + // assert + expect(request.state).toBeDefined(); + expect(request.state?.data).toEqual("foo"); + const url = request.url; + expect(url).toContain("http://sts/signout"); + expect(url).toContain("post_logout_redirect_uri=bar"); + expect(url).toContain("client_id=client"); + }); + + it("should pass params to SignoutRequest with client_id", async () => { + // arrange + jest.spyOn(subject.metadataService, "getEndSessionEndpoint").mockImplementation(() => Promise.resolve("http://sts/signout")); + + // act + const request = await subject.createSignoutRequest({ + state: "foo", + post_logout_redirect_uri: "bar", + client_id: "baz", + }); + + // assert + expect(request.state).toBeDefined(); + expect(request.state?.data).toEqual("foo"); + const url = request.url; + expect(url).toContain("http://sts/signout"); + expect(url).toContain("post_logout_redirect_uri=bar"); + expect(url).toContain("client_id=baz"); + }); + it("should fail if metadata fails", async () => { // arrange jest.spyOn(subject.metadataService, "getEndSessionEndpoint").mockRejectedValue(new Error("test")); diff --git a/src/OidcClient.ts b/src/OidcClient.ts index cb3846c74..777a8b923 100644 --- a/src/OidcClient.ts +++ b/src/OidcClient.ts @@ -218,6 +218,7 @@ export class OidcClient { public async createSignoutRequest({ state, id_token_hint, + client_id, request_type, post_logout_redirect_uri = this.settings.post_logout_redirect_uri, extraQueryParams = this.settings.extraQueryParams, @@ -232,9 +233,15 @@ export class OidcClient { logger.debug("Received end session endpoint", url); + // specify the client identifier when post_logout_redirect_uri is used but id_token_hint is not + if (!client_id && post_logout_redirect_uri && !id_token_hint) { + client_id = this.settings.client_id; + } + const request = new SignoutRequest({ url, id_token_hint, + client_id, post_logout_redirect_uri, state_data: state, extraQueryParams, diff --git a/src/SignoutRequest.ts b/src/SignoutRequest.ts index 4cb718300..a310f7dc6 100644 --- a/src/SignoutRequest.ts +++ b/src/SignoutRequest.ts @@ -14,6 +14,7 @@ export interface SignoutRequestArgs { // optional id_token_hint?: string; + client_id?: string; post_logout_redirect_uri?: string; extraQueryParams?: Record; @@ -34,7 +35,7 @@ export class SignoutRequest { public constructor({ url, - state_data, id_token_hint, post_logout_redirect_uri, extraQueryParams, request_type, + state_data, id_token_hint, post_logout_redirect_uri, extraQueryParams, request_type, client_id, }: SignoutRequestArgs) { if (!url) { this._logger.error("ctor: No url passed"); @@ -45,6 +46,9 @@ export class SignoutRequest { if (id_token_hint) { parsedUrl.searchParams.append("id_token_hint", id_token_hint); } + if (client_id) { + parsedUrl.searchParams.append("client_id", client_id); + } if (post_logout_redirect_uri) { parsedUrl.searchParams.append("post_logout_redirect_uri", post_logout_redirect_uri);