From 55b8a33a90aff58e1017c0265ff1440845dc40c5 Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Mon, 9 Sep 2024 14:27:54 +0200 Subject: [PATCH] feat: add FAPI 2.0 support --- .github/workflows/conformance.yml | 19 +++++++++++++++ README.md | 11 ++++----- lib/client.js | 39 +++++++++++++++++++++++++++++-- lib/issuer.js | 1 + types/index.d.ts | 1 + 5 files changed, 62 insertions(+), 9 deletions(-) diff --git a/.github/workflows/conformance.yml b/.github/workflows/conformance.yml index aca0b7b4..0b225afb 100644 --- a/.github/workflows/conformance.yml +++ b/.github/workflows/conformance.yml @@ -94,6 +94,25 @@ jobs: fapi_response_mode: jarm fapi_client_type: plain_oauth + # FAPI 2.0 Security Profile ID2 + - plan: fapi2-security-profile-id2-client-test-plan + client_auth_type: 'private_key_jwt' + sender_constrain: 'dpop' + - plan: fapi2-security-profile-id2-client-test-plan + client_auth_type: 'private_key_jwt' + sender_constrain: 'mtls' + - plan: fapi2-security-profile-id2-client-test-plan + client_auth_type: 'mtls' + sender_constrain: 'dpop' + - plan: fapi2-security-profile-id2-client-test-plan + client_auth_type: 'mtls' + sender_constrain: 'mtls' + + # FAPI 2.0 Message Signing ID1 + - plan: fapi2-message-signing-id1-client-test-plan + client_auth_type: 'mtls' + sender_constrain: 'mtls' + steps: - name: Checkout uses: actions/checkout@v4 diff --git a/README.md b/README.md index fa591a72..42596f5c 100644 --- a/README.md +++ b/README.md @@ -52,13 +52,11 @@ Updates to draft specifications are released as MINOR library versions, if you utilize these specification implementations consider using the tilde `~` operator in your package.json since breaking changes may be introduced as part of these version updates. -## Certification -[OpenID Certification][openid-certified-link] -Filip Skokan has [certified][openid-certified-link] that [openid-client][npm-url] -conforms to the following profiles of the OpenID Connectâ„¢ protocol +## [Certification](https://openid.net/certification/faq/) -- Basic, Implicit, Hybrid, Config, Dynamic, and Form Post RP -- FAPI 1.0 Advanced RP +[OpenID Certification](#certification) + +[Filip Skokan](https://github.com/panva) has [certified](https://openid.net/certification) that [this software](https://github.com/panva/node-openid-client) conforms to the Basic, Implicit, Hybrid, Config, Dynamic, FAPI 1.0, and FAPI 2.0 Relying Party Conformance Profiles of the OpenID Connectâ„¢ protocol. ## Sponsor @@ -304,7 +302,6 @@ See [Customizing (docs)][documentation-customizing]. [feature-par]: https://www.rfc-editor.org/rfc/rfc9126.html [feature-jar]: https://www.rfc-editor.org/rfc/rfc9101.html [feature-iss]: https://www.rfc-editor.org/rfc/rfc9207.html -[openid-certified-link]: https://openid.net/certification/ [passport-url]: http://passportjs.org [npm-url]: https://www.npmjs.com/package/openid-client [sponsor-auth0]: https://a0.to/try-auth0 diff --git a/lib/client.js b/lib/client.js index dc8f927c..12b72e94 100644 --- a/lib/client.js +++ b/lib/client.js @@ -191,7 +191,7 @@ class BaseClient { authorization_signed_response_alg: 'RS256', response_types: ['code'], token_endpoint_auth_method: 'client_secret_basic', - ...(this.fapi() + ...(this.fapi1() ? { grant_types: ['authorization_code', 'implicit'], id_token_signed_response_alg: 'PS256', @@ -201,6 +201,13 @@ class BaseClient { token_endpoint_auth_method: undefined, } : undefined), + ...(this.fapi2() + ? { + id_token_signed_response_alg: 'PS256', + authorization_signed_response_alg: 'PS256', + token_endpoint_auth_method: undefined, + } + : undefined), ...metadata, }; @@ -221,6 +228,26 @@ class BaseClient { } } + if (this.fapi2()) { + if ( + properties.tls_client_certificate_bound_access_tokens && + properties.dpop_bound_access_tokens + ) { + throw new TypeError( + 'either tls_client_certificate_bound_access_tokens or dpop_bound_access_tokens must be set to true', + ); + } + + if ( + !properties.tls_client_certificate_bound_access_tokens && + !properties.dpop_bound_access_tokens + ) { + throw new TypeError( + 'either tls_client_certificate_bound_access_tokens or dpop_bound_access_tokens must be set to true', + ); + } + } + handleCommonMistakes(this, metadata, properties); assertSigningAlgValuesSupport('token', this.issuer, properties); @@ -824,7 +851,7 @@ class BaseClient { }); } - if (this.fapi()) { + if (this.fapi1()) { if (!payload.s_hash && (tokenSet.state || state)) { throw new RPError({ message: 'missing required property s_hash', @@ -1631,9 +1658,17 @@ class BaseClient { } fapi() { + return this.fapi1() || this.fapi2(); + } + + fapi1() { return this.constructor.name === 'FAPI1Client'; } + fapi2() { + return this.constructor.name === 'FAPI2Client'; + } + async validateJARM(response) { const expectedAlg = this.authorization_signed_response_alg; const { payload } = await this.validateJWT(response, expectedAlg, ['iss', 'exp', 'aud']); diff --git a/lib/issuer.js b/lib/issuer.js index 3329e889..906e6a51 100644 --- a/lib/issuer.js +++ b/lib/issuer.js @@ -73,6 +73,7 @@ class Issuer { Object.defineProperties(this, { Client: { value: Client, enumerable: true }, FAPI1Client: { value: class FAPI1Client extends Client {}, enumerable: true }, + FAPI2Client: { value: class FAPI2Client extends Client {}, enumerable: true }, }); } diff --git a/types/index.d.ts b/types/index.d.ts index d6b5aa0f..c9408f2b 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -443,6 +443,7 @@ export class Issuer { Client: TypeOfGenericClient; FAPI1Client: TypeOfGenericClient; + FAPI2Client: TypeOfGenericClient; metadata: IssuerMetadata; [custom.http_options]: CustomHttpOptionsProvider;