Skip to content

Commit

Permalink
feat: add FAPI 2.0 support
Browse files Browse the repository at this point in the history
  • Loading branch information
panva committed Sep 9, 2024
1 parent 23f7b49 commit 55b8a33
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 9 deletions.
19 changes: 19 additions & 0 deletions .github/workflows/conformance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 4 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
[<img width="184" height="96" align="right" src="https://cdn.jsdelivr.net/gh/panva/node-openid-client@38cf016b0837e6d4116de3780b28d222d5780bc9/OpenID_Certified.png" alt="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
[<img width="96" height="50" align="right" src="https://user-images.githubusercontent.com/241506/166977513-7cd710a9-7f60-4944-aebe-a658e9f36375.png" alt="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

Expand Down Expand Up @@ -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
Expand Down
39 changes: 37 additions & 2 deletions lib/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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,
};

Expand All @@ -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);
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -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']);
Expand Down
1 change: 1 addition & 0 deletions lib/issuer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
});
}

Expand Down
1 change: 1 addition & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,7 @@ export class Issuer<TClient extends BaseClient = BaseClient> {
Client: TypeOfGenericClient<TClient>;

FAPI1Client: TypeOfGenericClient<TClient>;
FAPI2Client: TypeOfGenericClient<TClient>;

metadata: IssuerMetadata;
[custom.http_options]: CustomHttpOptionsProvider;
Expand Down

0 comments on commit 55b8a33

Please sign in to comment.