Add support for extra OIDC client metadata

fflorent 3 months ago
parent 2d2906c2e7
commit 454e97f1a7

@ -41,6 +41,10 @@
* Defaults to "PKCE,STATE".
* env GRIST_OIDC_IDP_ACR_VALUES
* A space-separated list of ACR values to request from the IdP. Optional.
* env GRIST_OIDC_IDP_EXTRA_CLIENT_METADATA
* A JSON object with extra client metadata to pass to openid-client. Optional.
* More info: https://github.com/panva/node-openid-client/tree/main/docs#new-clientmetadata-jwks-options
*
*
* This version of OIDCConfig has been tested with Keycloak OIDC IdP following the instructions
* at:
@ -58,7 +62,7 @@
import * as express from 'express';
import { GristLoginSystem, GristServer } from './GristServer';
import { Client, generators, Issuer, UserinfoResponse } from 'openid-client';
import { Client, ClientMetadata, generators, Issuer, UserinfoResponse } from 'openid-client';
import { Sessions } from './Sessions';
import log from 'app/server/lib/log';
import { AppSettings, appSettings } from './AppSettings';
@ -144,9 +148,14 @@ export class OIDCConfig {
defaultValue: false,
})!;
const extraMetadata: Partial<ClientMetadata> = JSON.parse(section.flag('extraClientMetadata').readString({
envVar: 'GRIST_OIDC_IDP_EXTRA_CLIENT_METADATA',
defaultValue: '{}'
})!);
this._enabledProtections = this._buildEnabledProtections(section);
this._redirectUrl = new URL(CALLBACK_URL, spHost).href;
await this._initClient({issuerUrl, clientId, clientSecret});
await this._initClient({issuerUrl, clientId, clientSecret, extraMetadata});
if (this._client.issuer.metadata.end_session_endpoint === undefined &&
!this._endSessionEndpoint && !this._skipEndSessionEndpoint) {
@ -231,8 +240,8 @@ export class OIDCConfig {
return this._enabledProtections.includes(protection);
}
protected async _initClient({issuerUrl, clientId, clientSecret}:
{issuerUrl: string, clientId: string, clientSecret: string}
protected async _initClient({issuerUrl, clientId, clientSecret, extraMetadata}:
{issuerUrl: string, clientId: string, clientSecret: string, extraMetadata: Partial<ClientMetadata> }
): Promise<void> {
const issuer = await Issuer.discover(issuerUrl);
this._client = new issuer.Client({
@ -240,6 +249,7 @@ export class OIDCConfig {
client_secret: clientSecret,
redirect_uris: [ this._redirectUrl ],
response_types: [ 'code' ],
...extraMetadata,
});
}

@ -106,6 +106,7 @@ describe('OIDCConfig', () => {
clientId: process.env.GRIST_OIDC_IDP_CLIENT_ID,
clientSecret: process.env.GRIST_OIDC_IDP_CLIENT_SECRET,
issuerUrl: process.env.GRIST_OIDC_IDP_ISSUER,
extraMetadata: {},
}]);
assert.isTrue(logInfoStub.calledOnce);
assert.deepEqual(
@ -114,6 +115,23 @@ describe('OIDCConfig', () => {
);
});
it('should create a client with passed information with extra configuration', async () => {
setEnvVars();
const extraMetadata = {
userinfo_signed_response_alg: 'RS256',
};
process.env.GRIST_OIDC_IDP_EXTRA_CLIENT_METADATA = JSON.stringify(extraMetadata);
const client = new ClientStub();
const config = await OIDCConfigStubbed.build(client.asClient());
assert.isTrue(config._initClient.calledOnce);
assert.deepEqual(config._initClient.firstCall.args, [{
clientId: process.env.GRIST_OIDC_IDP_CLIENT_ID,
clientSecret: process.env.GRIST_OIDC_IDP_CLIENT_SECRET,
issuerUrl: process.env.GRIST_OIDC_IDP_ISSUER,
extraMetadata,
}]);
});
describe('End Session Endpoint', () => {
[
{

Loading…
Cancel
Save