Skip to content

Commit

Permalink
feat: update JWT Response for OAuth Token Introspection to draft 08
Browse files Browse the repository at this point in the history
  • Loading branch information
panva committed Sep 23, 2019
1 parent 10d9fb1 commit 5f917e2
Show file tree
Hide file tree
Showing 8 changed files with 31 additions and 16 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ enabled by default, check the configuration section on how to enable them.

The following draft specifications are implemented by oidc-provider.
- [JSON Web Token (JWT) Profile for OAuth 2.0 Access Tokens - draft 02][jwt-at]
- [JWT Response for OAuth Token Introspection - draft 07][jwt-introspection]
- [JWT Response for OAuth Token Introspection - draft 08][jwt-introspection]
- [JWT Secured Authorization Response Mode for OAuth 2.0 (JARM) - draft 02][jarm]
- [OAuth 2.0 Demonstration of Proof-of-Possession at the Application Layer (DPoP) - individual draft 02][dpop]
- [OAuth 2.0 JWT Secured Authorization Request (JAR)][jar]
Expand Down Expand Up @@ -205,7 +205,7 @@ See the list of available emitted [event names](/docs/events.md) and their descr
[wmrm]: https://tools.ietf.org/html/draft-sakimura-oauth-wmrm-00
[jar]: https://tools.ietf.org/html/draft-ietf-oauth-jwsreq-19
[device-flow]: https://tools.ietf.org/html/rfc8628
[jwt-introspection]: https://tools.ietf.org/html/draft-ietf-oauth-jwt-introspection-response-07
[jwt-introspection]: https://tools.ietf.org/html/draft-ietf-oauth-jwt-introspection-response-08
[sponsor-auth0]: https://auth0.com/overview?utm_source=GHsponsor&utm_medium=GHsponsor&utm_campaign=oidc-provider&utm_content=auth
[suggest-feature]: https://github.com/panva/node-oidc-provider/issues/new?template=feature-request.md
[bug]: https://github.com/panva/node-oidc-provider/issues/new?template=bug-report.md
Expand Down
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1051,7 +1051,7 @@ _**default value**_:

### features.jwtIntrospection

[draft-ietf-oauth-jwt-introspection-response-06](https://tools.ietf.org/html/draft-ietf-oauth-jwt-introspection-response-06) - JWT Response for OAuth Token Introspection
[draft-ietf-oauth-jwt-introspection-response-08](https://tools.ietf.org/html/draft-ietf-oauth-jwt-introspection-response-08) - JWT Response for OAuth Token Introspection

Enables JWT responses for Token Introspection features

Expand Down
9 changes: 6 additions & 3 deletions lib/actions/introspection.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const Debug = require('debug');
const debug = new Debug('oidc-provider:introspection');
const uidToGrantId = new Debug('oidc-provider:uid');

const epochTime = require('../helpers/epoch_time');
const presence = require('../helpers/validate_presence');
const getTokenAuth = require('../shared/token_auth');
const noCache = require('../shared/no_cache');
Expand Down Expand Up @@ -78,19 +79,21 @@ module.exports = function introspectionAction(provider) {
const {
introspectionEncryptedResponseAlg: encrypt,
introspectionSignedResponseAlg: sign,
introspectionEndpointAuthMethod: method,
} = client;

const accepts = ctx.accepts('json', JWT);
if (encrypt && method === 'none' && accepts !== JWT) {
if (encrypt && accepts !== JWT) {
throw new InvalidRequest(`introspection must be requested with Accept: ${JWT} for this client`);
}

await next();

if ((encrypt || sign) && accepts === JWT) {
const token = new IdToken({}, { ctx });
token.extra = ctx.body;
token.extra = {
...ctx.body,
iat: ctx.body.iat ? epochTime() : undefined,
};

ctx.body = await token.issue({ use: 'introspection' });
ctx.type = 'application/jwt; charset=utf-8';
Expand Down
2 changes: 1 addition & 1 deletion lib/helpers/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -817,7 +817,7 @@ const DEFAULTS = {
/*
* features.jwtIntrospection
*
* title: [draft-ietf-oauth-jwt-introspection-response-06](https://tools.ietf.org/html/draft-ietf-oauth-jwt-introspection-response-06) - JWT Response for OAuth Token Introspection
* title: [draft-ietf-oauth-jwt-introspection-response-08](https://tools.ietf.org/html/draft-ietf-oauth-jwt-introspection-response-08) - JWT Response for OAuth Token Introspection
*
* description: Enables JWT responses for Token Introspection features
*
Expand Down
6 changes: 3 additions & 3 deletions lib/helpers/features.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@ const DRAFTS = new Map(Object.entries({
version: 2,
},
jwtIntrospection: {
name: 'JWT Response for OAuth Token Introspection - draft 07',
name: 'JWT Response for OAuth Token Introspection - draft 08',
type: 'IETF OAuth Working Group draft',
url: 'https://tools.ietf.org/html/draft-ietf-oauth-jwt-introspection-response-07',
version: [2, 3, 4, 5, 6, 7],
url: 'https://tools.ietf.org/html/draft-ietf-oauth-jwt-introspection-response-08',
version: 8,
},
jwtResponseModes: {
name: 'JWT Secured Authorization Response Mode for OAuth 2.0 - draft 02',
Expand Down
1 change: 1 addition & 0 deletions lib/models/id_token.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ module.exports = function getIdToken(provider) {
alg = client.introspectionSignedResponseAlg;
signOptions = {
noIat: true,
typ: 'token-introspection+jwt',
};
encryption = {
alg: client.introspectionEncryptedResponseAlg,
Expand Down
2 changes: 1 addition & 1 deletion test/jwt_introspection/jwt_introspection.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ module.exports = {
redirect_uris: ['https://client.example.com/cb'],
},
{
client_id: 'client-encrypted-none',
client_id: 'client-encrypted',
client_secret: 'secret',
introspection_endpoint_auth_method: 'none',
introspection_encrypted_response_alg: 'PBES2-HS256+A128KW',
Expand Down
21 changes: 16 additions & 5 deletions test/jwt_introspection/jwt_introspection.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const { expect } = require('chai');
const timekeeper = require('timekeeper');

const bootstrap = require('../test_helper');
const JWT = require('../../lib/helpers/jwt');
Expand All @@ -9,6 +10,8 @@ const route = '/token/introspection';
describe('jwtIntrospection features', () => {
before(bootstrap(__dirname));

afterEach(() => timekeeper.reset());

describe('enriched discovery', () => {
it('shows the url now', function () {
return this.agent.get('/.well-known/openid-configuration')
Expand All @@ -31,6 +34,8 @@ describe('jwtIntrospection features', () => {
});

it('returns the response as jwt', async function () {
const now = Date.now();
timekeeper.freeze(now);
const at = new this.provider.AccessToken({
accountId: 'accountId',
grantId: 'foo',
Expand All @@ -39,6 +44,7 @@ describe('jwtIntrospection features', () => {
});

let json;
let iat;
const token = await at.save();
await this.agent.post(route)
.auth('client-signed', 'secret')
Expand All @@ -49,9 +55,11 @@ describe('jwtIntrospection features', () => {
.expect(200)
.expect('content-type', 'application/json; charset=utf-8')
.expect(({ body }) => {
json = body;
({ iat, ...json } = body);
});

timekeeper.travel(now + (10 * 1000));

return this.agent.post(route)
.auth('client-signed', 'secret')
.send({
Expand All @@ -62,7 +70,10 @@ describe('jwtIntrospection features', () => {
.expect(200)
.expect('content-type', 'application/jwt; charset=utf-8')
.expect(({ text }) => {
expect(JWT.decode(text).payload).to.eql(json);
const { payload: { iat: jwtIat, ...payload }, header } = JWT.decode(text);
expect(payload).to.eql(json);
expect(jwtIat).to.eql(iat + 10);
expect(header).to.have.property('typ', 'token-introspection+jwt');
});
});

Expand Down Expand Up @@ -95,14 +106,14 @@ describe('jwtIntrospection features', () => {
const at = new this.provider.AccessToken({
accountId: 'accountId',
grantId: 'foo',
clientId: 'client-encrypted-none',
clientId: 'client-encrypted',
scope: 'scope',
});

const token = await at.save();
await this.agent.post(route)
.send({
client_id: 'client-encrypted-none',
client_id: 'client-encrypted',
token,
})
.type('form')
Expand All @@ -115,7 +126,7 @@ describe('jwtIntrospection features', () => {

return this.agent.post(route)
.send({
client_id: 'client-encrypted-none',
client_id: 'client-encrypted',
token,
})
.type('form')
Expand Down

0 comments on commit 5f917e2

Please sign in to comment.