feat(openid): add the openid connect `at_hash` value
This commit is contained in:
Родитель
fc17ee50ad
Коммит
a42ba28e57
|
@ -448,14 +448,15 @@ function _validateJwtSub(sub) {
|
|||
return sub;
|
||||
}
|
||||
|
||||
function generateIdToken(options) {
|
||||
function generateIdToken(options, access) {
|
||||
var now = Math.floor(Date.now() / 1000);
|
||||
var claims = {
|
||||
sub: hex(options.userId),
|
||||
aud: hex(options.clientId),
|
||||
iss: ID_TOKEN_ISSUER,
|
||||
iat: now,
|
||||
exp: now + ID_TOKEN_EXPIRATION
|
||||
exp: now + ID_TOKEN_EXPIRATION,
|
||||
at_hash: util.generateTokenHash(access.token)
|
||||
};
|
||||
if (options.amr) {
|
||||
claims.amr = options.amr;
|
||||
|
@ -467,42 +468,43 @@ function generateIdToken(options) {
|
|||
return ID_TOKEN_KEY.sign(claims);
|
||||
}
|
||||
|
||||
function generateTokens(options) {
|
||||
function generateTokens (options) {
|
||||
// we always are generating an access token here
|
||||
// but depending on options, we may also be generating a refresh_token
|
||||
var promises = {
|
||||
access: db.generateAccessToken(options)
|
||||
};
|
||||
if (options.offline) {
|
||||
promises.refresh = db.generateRefreshToken(options);
|
||||
}
|
||||
if (options.idToken) {
|
||||
promises.idToken = generateIdToken(options);
|
||||
}
|
||||
return P.props(promises).then(function(result) {
|
||||
var access = result.access;
|
||||
var refresh = result.refresh;
|
||||
var idToken = result.idToken;
|
||||
return db.generateAccessToken(options)
|
||||
.then((access) => {
|
||||
const promises = {};
|
||||
if (options.offline) {
|
||||
promises.refresh = db.generateRefreshToken(options);
|
||||
}
|
||||
if (options.idToken) {
|
||||
promises.idToken = generateIdToken(options, access);
|
||||
}
|
||||
|
||||
var json = {
|
||||
access_token: access.token.toString('hex'),
|
||||
token_type: access.type,
|
||||
scope: access.scope.toString()
|
||||
};
|
||||
if (options.authAt) {
|
||||
json.auth_at = options.authAt;
|
||||
}
|
||||
json.expires_in = options.ttl;
|
||||
if (refresh) {
|
||||
json.refresh_token = refresh.token.toString('hex');
|
||||
}
|
||||
if (idToken) {
|
||||
json.id_token = idToken;
|
||||
}
|
||||
if (options.keysJwe) {
|
||||
json.keys_jwe = options.keysJwe;
|
||||
}
|
||||
return json;
|
||||
});
|
||||
return P.props(promises).then(function (result) {
|
||||
const refresh = result.refresh;
|
||||
const idToken = result.idToken;
|
||||
|
||||
const json = {
|
||||
access_token: access.token.toString('hex'),
|
||||
token_type: access.type,
|
||||
scope: access.scope.toString()
|
||||
};
|
||||
if (options.authAt) {
|
||||
json.auth_at = options.authAt;
|
||||
}
|
||||
json.expires_in = options.ttl;
|
||||
if (refresh) {
|
||||
json.refresh_token = refresh.token.toString('hex');
|
||||
}
|
||||
if (idToken) {
|
||||
json.id_token = idToken;
|
||||
}
|
||||
if (options.keysJwe) {
|
||||
json.keys_jwe = options.keysJwe;
|
||||
}
|
||||
return json;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
23
lib/util.js
23
lib/util.js
|
@ -2,6 +2,8 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const encrypt = require('./encrypt');
|
||||
|
||||
/**
|
||||
* .base64URLEncode
|
||||
*
|
||||
|
@ -22,6 +24,23 @@ const base64URLEncode = function base64URLEncode(buf) {
|
|||
.replace(/=/g, '');
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
base64URLEncode: base64URLEncode
|
||||
/**
|
||||
* Generates a hash of the access token based on
|
||||
* http://openid.net/specs/openid-connect-core-1_0.html#CodeIDToken
|
||||
*
|
||||
* This value is the hash of the ascii value of the access token, then the base64url
|
||||
* value of the left half.
|
||||
*
|
||||
* @param {Buffer} accessTokenBuf
|
||||
* @returns {String}
|
||||
* @api public
|
||||
*/
|
||||
const generateTokenHash = function generateTokenHash (accessTokenBuf) {
|
||||
const hash = encrypt.hash(accessTokenBuf.toString('ascii'));
|
||||
return base64URLEncode(hash.slice(0, hash.length / 2));
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
base64URLEncode: base64URLEncode,
|
||||
generateTokenHash: generateTokenHash
|
||||
};
|
||||
|
|
|
@ -17,6 +17,7 @@ const encrypt = require('../lib/encrypt');
|
|||
const P = require('../lib/promise');
|
||||
const Server = require('./lib/server');
|
||||
const unique = require('../lib/unique');
|
||||
const util = require('../lib/util');
|
||||
|
||||
const assertSecurityHeaders = require('./lib/util').assertSecurityHeaders;
|
||||
|
||||
|
@ -1952,6 +1953,9 @@ describe('/v1', function() {
|
|||
assert.deepEqual(claims.amr, AMR);
|
||||
assert.equal(claims.acr, ACR);
|
||||
assert.equal(claims['fxa-aal'], AAL);
|
||||
|
||||
const at_hash = util.generateTokenHash(Buffer.from(res.result.access_token, 'hex'));
|
||||
assert.equal(claims.at_hash, at_hash);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче