Skip to content

Commit

Permalink
[SDK-3109] Add ability to pass custom logout params (#329)
Browse files Browse the repository at this point in the history
* Add ability to pass custom logout params

* Revert basic example
  • Loading branch information
adamjmcgrath authored Feb 17, 2022
1 parent c8475cc commit cc59bec
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 1 deletion.
1 change: 1 addition & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"extends": "eslint:recommended",
"rules": {
"no-useless-escape": 1,
"no-unused-vars": ["error", { "vars": "all", "args": "after-used", "ignoreRestSiblings": true }],
"no-console": 0,
"linebreak-style": ["error", "unix"]
},
Expand Down
10 changes: 10 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,11 @@ interface LogoutOptions {
* URL to returnTo after logout, overrides the Default in {@link ConfigParams.routes.postLogoutRedirect routes.postLogoutRedirect}
*/
returnTo?: string;

/**
* Additional custom parameters to pass to the logout endpoint.
*/
logoutParams?: { [key: string]: any };
}

/**
Expand Down Expand Up @@ -303,6 +308,11 @@ interface ConfigParams {
*/
authorizationParams?: AuthorizationParameters;

/**
* Additional custom parameters to pass to the logout endpoint.
*/
logoutParams?: { [key: string]: any };

/**
* REQUIRED. The root URL for the application router, eg https://localhost
* Can use env key BASE_URL instead.
Expand Down
15 changes: 14 additions & 1 deletion lib/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,24 @@ async function get(config) {
) {
Object.defineProperty(client, 'endSessionUrl', {
value(params) {
const {
id_token_hint,
post_logout_redirect_uri,
...extraParams
} = params;
const parsedUrl = url.parse(urlJoin(issuer.issuer, '/v2/logout'));
parsedUrl.query = {
returnTo: params.post_logout_redirect_uri,
...extraParams,
returnTo: post_logout_redirect_uri,
client_id: client.client_id,
};

Object.entries(parsedUrl.query).forEach(([key, value]) => {
if (value === null || value === undefined) {
delete parsedUrl.query[key];
}
});

return url.format(parsedUrl);
},
});
Expand Down
1 change: 1 addition & 0 deletions lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ const paramsSchema = Joi.object({
.optional()
.unknown(true)
.default(),
logoutParams: Joi.object().optional(),
baseURL: Joi.string()
.uri()
.required()
Expand Down
2 changes: 2 additions & 0 deletions lib/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,8 @@ class ResponseContext {

try {
returnURL = client.endSessionUrl({
...config.logoutParams,
...params.logoutParams,
post_logout_redirect_uri: returnURL,
id_token_hint,
});
Expand Down
110 changes: 110 additions & 0 deletions test/logout.tests.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const { assert } = require('chai');
const { URL } = require('url');
const { create: createServer } = require('./fixture/server');
const { makeIdToken } = require('./fixture/cert');
const { auth } = require('./..');
Expand Down Expand Up @@ -210,4 +211,113 @@ describe('logout route', async () => {
jar.getCookies(baseUrl).find(({ key }) => key === 'skipSilentLogin')
);
});

it('should pass logout params to end session url', async () => {
server = await createServer(
auth({ ...defaultConfig, idpLogout: true, logoutParams: { foo: 'bar' } })
);

const { jar } = await login();
const {
response: {
headers: { location },
},
} = await logout(jar);
const params = new URL(location).searchParams;
assert.equal(params.get('foo'), 'bar');
});

it('should override logout params per request', async () => {
const router = auth({
...defaultConfig,
idpLogout: true,
logoutParams: { foo: 'bar' },
routes: { logout: false },
});
server = await createServer(router);
router.get('/logout', (req, res) =>
res.oidc.logout({ logoutParams: { foo: 'baz' } })
);

const { jar } = await login();
const {
response: {
headers: { location },
},
} = await logout(jar);
const params = new URL(location).searchParams;
assert.equal(params.get('foo'), 'baz');
});

it('should pass logout params to auth0 logout url', async () => {
server = await createServer(
auth({
...defaultConfig,
issuerBaseURL: 'https://test.eu.auth0.com',
idpLogout: true,
auth0Logout: true,
logoutParams: { foo: 'bar' },
})
);

const { jar } = await login();
const {
response: {
headers: { location },
},
} = await logout(jar);
const url = new URL(location);
assert.equal(url.pathname, '/v2/logout');
assert.equal(url.searchParams.get('foo'), 'bar');
});

it('should honor logout url config over logout params', async () => {
server = await createServer(
auth({
...defaultConfig,
routes: { postLogoutRedirect: 'http://foo.com' },
idpLogout: true,
logoutParams: {
foo: 'bar',
post_logout_redirect_uri: 'http://bar.com',
},
})
);

const { jar } = await login();
const {
response: {
headers: { location },
},
} = await logout(jar);
const url = new URL(
new URL(location).searchParams.get('post_logout_redirect_uri')
);
assert.equal(url.hostname, 'foo.com');
});

it('should ignore undefined or null logout params', async () => {
server = await createServer(
auth({
...defaultConfig,
issuerBaseURL: 'https://test.eu.auth0.com',
idpLogout: true,
auth0Logout: true,
logoutParams: { foo: 'bar', bar: undefined, baz: null, qux: '' },
})
);

const { jar } = await login();
const {
response: {
headers: { location },
},
} = await logout(jar);
const url = new URL(location);
assert.equal(url.pathname, '/v2/logout');
assert.equal(url.searchParams.get('foo'), 'bar');
assert.isFalse(url.searchParams.has('bar'));
assert.isFalse(url.searchParams.has('baz'));
assert.equal(url.searchParams.get('qux'), '');
});
});

0 comments on commit cc59bec

Please sign in to comment.