Skip to content

Commit

Permalink
feat: OAuth 2.0 Pushed Authorization Requests (PAR) is now a stable f…
Browse files Browse the repository at this point in the history
…eature
  • Loading branch information
panva committed Sep 15, 2021
1 parent fb5a7ba commit 327f366
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 70 deletions.
6 changes: 4 additions & 2 deletions README.md
Expand Up @@ -42,12 +42,13 @@ openid-client.
- Client Authentication
- tls_client_auth
- self_signed_tls_client_auth
- [RFC9101 - OAuth 2.0 JWT-Secured Authorization Request (JAR)][feature-jar]
- [RFC9126 - OAuth 2.0 Pushed Authorization Requests (PAR)][feature-par]
- [OpenID Connect Session Management 1.0 - draft 28][feature-rp-logout]
- RP-Initiated Logout
- [Financial-grade API - Part 2: Read and Write API Security Profile (FAPI) - ID2][feature-fapi]
- [JWT Secured Authorization Response Mode for OAuth 2.0 (JARM) - ID1][feature-jarm]
- [OAuth 2.0 Demonstration of Proof-of-Possession at the Application Layer (DPoP) - draft 01][feature-dpop]
- [OAuth 2.0 Pushed Authorization Requests (PAR) - draft 06][feature-par]

Updates to draft specifications (DPoP, JARM, and FAPI) are released as MINOR library versions,
if you utilize these specification implementations consider using the tilde `~` operator in your
Expand Down Expand Up @@ -297,7 +298,8 @@ See [Customizing (docs)](https://github.com/panva/node-openid-client/blob/master
[feature-jarm]: https://openid.net/specs/openid-financial-api-jarm-ID1.html
[feature-fapi]: https://openid.net/specs/openid-financial-api-part-2-ID2.html
[feature-dpop]: https://tools.ietf.org/html/draft-ietf-oauth-dpop-01
[feature-par]: https://tools.ietf.org/html/draft-ietf-oauth-par-06
[feature-par]: https://www.rfc-editor.org/rfc/rfc9126.html
[feature-jar]: https://www.rfc-editor.org/rfc/rfc9101.html
[openid-certified-link]: https://openid.net/certification/
[passport-url]: http://passportjs.org
[npm-url]: https://www.npmjs.com/package/openid-client
Expand Down
119 changes: 51 additions & 68 deletions lib/client.js
Expand Up @@ -1550,6 +1550,57 @@ module.exports = (issuer, aadIssValidation = false) => class Client extends Base
});
}

/**
* @name pushedAuthorizationRequest
* @api public
*/
async pushedAuthorizationRequest(params = {}, { clientAssertionPayload } = {}) {
assertIssuerConfiguration(this.issuer, 'pushed_authorization_request_endpoint');

const body = {
...('request' in params ? params : authorizationParams.call(this, params)),
client_id: this.client_id,
};

const response = await authenticatedPost.call(
this,
'pushed_authorization_request',
{
responseType: 'json',
form: body,
},
{ clientAssertionPayload, endpointAuthMethod: 'token' },
);
const responseBody = processResponse(response, { statusCode: 201 });

if (!('expires_in' in responseBody)) {
throw new RPError({
message: 'expected expires_in in Pushed Authorization Successful Response',
response,
});
}
if (typeof responseBody.expires_in !== 'number') {
throw new RPError({
message: 'invalid expires_in value in Pushed Authorization Successful Response',
response,
});
}
if (!('request_uri' in responseBody)) {
throw new RPError({
message: 'expected request_uri in Pushed Authorization Successful Response',
response,
});
}
if (typeof responseBody.request_uri !== 'string') {
throw new RPError({
message: 'invalid request_uri value in Pushed Authorization Successful Response',
response,
});
}

return responseBody;
}

/**
* @name issuer
* @api public
Expand Down Expand Up @@ -1660,72 +1711,4 @@ Object.defineProperty(BaseClient.prototype, 'dpopProof', {
},
});

/**
* @name pushedAuthorizationRequest
* @api public
*/
async function pushedAuthorizationRequest(params = {}, { clientAssertionPayload } = {}) {
assertIssuerConfiguration(this.issuer, 'pushed_authorization_request_endpoint');

const body = {
...('request' in params ? params : authorizationParams.call(this, params)),
client_id: this.client_id,
};

const response = await authenticatedPost.call(
this,
'pushed_authorization_request',
{
responseType: 'json',
form: body,
},
{ clientAssertionPayload, endpointAuthMethod: 'token' },
);
const responseBody = processResponse(response, { statusCode: 201 });

if (!('expires_in' in responseBody)) {
throw new RPError({
message: 'expected expires_in in Pushed Authorization Successful Response',
response,
});
}
if (typeof responseBody.expires_in !== 'number') {
throw new RPError({
message: 'invalid expires_in value in Pushed Authorization Successful Response',
response,
});
}
if (!('request_uri' in responseBody)) {
throw new RPError({
message: 'expected request_uri in Pushed Authorization Successful Response',
response,
});
}
if (typeof responseBody.request_uri !== 'string') {
throw new RPError({
message: 'invalid request_uri value in Pushed Authorization Successful Response',
response,
});
}

return responseBody;
}

Object.defineProperty(BaseClient.prototype, 'pushedAuthorizationRequest', {
enumerable: true,
configurable: true,
value(...args) {
process.emitWarning(
'The Pushed Authorization Requests APIs implements an IETF draft. Breaking draft implementations are included as minor versions of the openid-client library, therefore, the ~ semver operator should be used and close attention be payed to library changelog as well as the drafts themselves.',
'DraftWarning',
);
Object.defineProperty(BaseClient.prototype, 'pushedAuthorizationRequest', {
enumerable: true,
configurable: true,
value: pushedAuthorizationRequest,
});
return this.pushedAuthorizationRequest(...args);
},
});

module.exports.BaseClient = BaseClient;

0 comments on commit 327f366

Please sign in to comment.