Skip to content

Commit

Permalink
Provide option to skip idToken signature validation
Browse files Browse the repository at this point in the history
  • Loading branch information
jmelberg-okta committed Jun 28, 2018
1 parent 666e7b6 commit 825f307
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 22 deletions.
4 changes: 4 additions & 0 deletions lib/clientBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ function OktaAuthBuilder(args) {
this.options.maxClockSkew = args.maxClockSkew;
}

// Give the developer the ability to disable token signature
// validation.
this.options.ignoreSignature = args.ignoreSignature === true ? true : false;

sdk.session = {
close: util.bind(session.closeSession, null, sdk),
exists: util.bind(session.sessionExists, null, sdk),
Expand Down
7 changes: 5 additions & 2 deletions lib/oauthUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,15 @@ function getKey(sdk, issuer, kid) {
});
}

function validateClaims(sdk, claims, aud, iss, nonce) {
function validateClaims(sdk, claims, validationParams) {
var aud = validationParams.clientId;
var iss = validationParams.issuer;

if (!claims || !iss || !aud) {
throw new AuthSdkError('The jwt, iss, and aud arguments are all required');
}

if (nonce && claims.nonce !== nonce) {
if (validationParams.nonce && claims.nonce !== validationParams.nonce) {
throw new AuthSdkError('OAuth flow response nonce doesn\'t match request nonce');
}

Expand Down
37 changes: 32 additions & 5 deletions lib/token.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ function decodeToken(token) {
return decodedToken;
}

function verifyToken(sdk, token, nonce, ignoreSignature) {
function verifyToken(sdk, token, validationParams) {
return new Q()
.then(function() {
if (!token || !token.idToken) {
Expand All @@ -48,12 +48,15 @@ function verifyToken(sdk, token, nonce, ignoreSignature) {

var jwt = decodeToken(token.idToken);

// Default validation params
var validationOptions = getDefaultValidationParams(sdk, validationParams);

// Standard claim validation
oauthUtil.validateClaims(sdk, jwt.payload, token.clientId, token.issuer, nonce);
oauthUtil.validateClaims(sdk, jwt.payload, validationOptions);

// If the browser doesn't support native crypto or we choose not
// to verify the signature, bail early
if (ignoreSignature || !sdk.features.isTokenVerifySupported()) {
if (validationOptions.ignoreSignature == true || !sdk.features.isTokenVerifySupported()) {
return token;
}

Expand Down Expand Up @@ -125,6 +128,7 @@ function handleOAuthResponse(sdk, oauthParams, res, urls) {
var tokenTypes = oauthParams.responseType;
var scopes = util.clone(oauthParams.scopes);
var clientId = oauthParams.clientId || sdk.options.clientId;
var ignoreSignature = oauthParams.ignoreSignature;

return new Q()
.then(function() {
Expand Down Expand Up @@ -168,7 +172,14 @@ function handleOAuthResponse(sdk, oauthParams, res, urls) {
clientId: clientId
};

return verifyToken(sdk, idToken, oauthParams.nonce, true)
var validationParams = {
clientId: clientId,
issuer: urls.issuer,
nonce: oauthParams.nonce,
ignoreSignature: ignoreSignature
};

return verifyToken(sdk, idToken, validationParams)
.then(function() {
tokenDict['id_token'] = idToken;
return tokenDict;
Expand Down Expand Up @@ -203,7 +214,20 @@ function getDefaultOAuthParams(sdk, oauthOptions) {
responseMode: 'okta_post_message',
state: util.genRandomString(64),
nonce: util.genRandomString(64),
scopes: ['openid', 'email']
scopes: ['openid', 'email'],
ignoreSignature: sdk.options.ignoreSignature
};
util.extend(defaults, oauthOptions);
return defaults;
}

function getDefaultValidationParams(sdk, oauthOptions) {
oauthOptions = util.clone(oauthOptions) || {};

var defaults = {
clientId: sdk.options.clientId,
issuer: sdk.options.issuer || sdk.options.url,
ignoreSignature: sdk.options.ignoreSignature
};
util.extend(defaults, oauthOptions);
return defaults;
Expand Down Expand Up @@ -481,6 +505,7 @@ function getWithRedirect(sdk, oauthOptions, options) {
state: oauthParams.state,
nonce: oauthParams.nonce,
scopes: oauthParams.scopes,
clientId: oauthParams.clientId,
urls: urls
}));

Expand All @@ -500,11 +525,13 @@ function refreshToken(sdk, token) {
}

var responseType;

if (token.accessToken) {
responseType = 'token';
} else {
responseType = 'id_token';
}

return sdk.token.getWithoutPrompt({
responseType: responseType,
scopes: token.scopes
Expand Down
89 changes: 77 additions & 12 deletions test/spec/token.js
Original file line number Diff line number Diff line change
Expand Up @@ -947,6 +947,7 @@ define(function(require) {
state: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
nonce: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
scopes: ['openid', 'email'],
clientId: 'NPSfOkH5eZrTy8PMDlvx',
urls: {
issuer: 'https://auth-js-test.okta.com',
authorizeUrl: 'https://auth-js-test.okta.com/oauth2/v1/authorize',
Expand Down Expand Up @@ -984,6 +985,7 @@ define(function(require) {
state: oauthUtil.mockedState,
nonce: oauthUtil.mockedNonce,
scopes: ['openid', 'email'],
clientId: 'NPSfOkH5eZrTy8PMDlvx',
urls: {
issuer: 'https://auth-js-test.okta.com/oauth2/aus8aus76q8iphupD0h7',
authorizeUrl: 'https://auth-js-test.okta.com/oauth2/aus8aus76q8iphupD0h7/v1/authorize',
Expand Down Expand Up @@ -1025,6 +1027,51 @@ define(function(require) {
state: oauthUtil.mockedState,
nonce: oauthUtil.mockedNonce,
scopes: ['email'],
clientId: 'NPSfOkH5eZrTy8PMDlvx',
urls: {
issuer: 'https://auth-js-test.okta.com/oauth2/aus8aus76q8iphupD0h7',
authorizeUrl: 'https://auth-js-test.okta.com/oauth2/aus8aus76q8iphupD0h7/v1/authorize',
userinfoUrl: 'https://auth-js-test.okta.com/oauth2/aus8aus76q8iphupD0h7/v1/userinfo'
}
}) + '; path=/;',
'okta-oauth-nonce=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; path=/;',
'okta-oauth-state=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; path=/;'
],
expectedRedirectUrl: 'https://auth-js-test.okta.com/oauth2/aus8aus76q8iphupD0h7/v1/authorize?' +
'client_id=NPSfOkH5eZrTy8PMDlvx&' +
'redirect_uri=https%3A%2F%2Fexample.com%2Fredirect&' +
'response_type=token&' +
'response_mode=fragment&' +
'state=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&' +
'nonce=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&' +
'sessionToken=testToken&' +
'scope=email'
});
});

it('allows passing issuer through getWithRedirect, which takes precedence', function() {
oauthUtil.setupRedirect({
oktaAuthArgs: {
url: 'https://auth-js-test.okta.com',
clientId: 'foo',
redirectUri: 'https://example.com/redirect',
issuer: 'https://auth-js-test.okta.com/oauth2/ORIGINAL_AUTH_SERVER_ID'
},
getWithRedirectArgs: [{
responseType: 'token',
scopes: ['email'],
sessionToken: 'testToken',
clientId: 'NPSfOkH5eZrTy8PMDlvx'
}, {
issuer: 'https://auth-js-test.okta.com/oauth2/aus8aus76q8iphupD0h7'
}],
expectedCookies: [
'okta-oauth-redirect-params=' + JSON.stringify({
responseType: 'token',
state: oauthUtil.mockedState,
nonce: oauthUtil.mockedNonce,
scopes: ['email'],
clientId: 'NPSfOkH5eZrTy8PMDlvx',
urls: {
issuer: 'https://auth-js-test.okta.com/oauth2/aus8aus76q8iphupD0h7',
authorizeUrl: 'https://auth-js-test.okta.com/oauth2/aus8aus76q8iphupD0h7/v1/authorize',
Expand Down Expand Up @@ -1059,6 +1106,7 @@ define(function(require) {
state: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
nonce: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
scopes: ['email'],
clientId: 'NPSfOkH5eZrTy8PMDlvx',
urls: {
issuer: 'https://auth-js-test.okta.com',
authorizeUrl: 'https://auth-js-test.okta.com/oauth2/v1/authorize',
Expand Down Expand Up @@ -1098,6 +1146,7 @@ define(function(require) {
state: oauthUtil.mockedState,
nonce: oauthUtil.mockedNonce,
scopes: ['email'],
clientId: 'NPSfOkH5eZrTy8PMDlvx',
urls: {
issuer: 'https://auth-js-test.okta.com/oauth2/aus8aus76q8iphupD0h7',
authorizeUrl: 'https://auth-js-test.okta.com/oauth2/aus8aus76q8iphupD0h7/v1/authorize',
Expand Down Expand Up @@ -1131,6 +1180,7 @@ define(function(require) {
state: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
nonce: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
scopes: ['openid', 'email'],
clientId: 'NPSfOkH5eZrTy8PMDlvx',
urls: {
issuer: 'https://auth-js-test.okta.com',
authorizeUrl: 'https://auth-js-test.okta.com/oauth2/v1/authorize',
Expand Down Expand Up @@ -1169,6 +1219,7 @@ define(function(require) {
state: oauthUtil.mockedState,
nonce: oauthUtil.mockedNonce,
scopes: ['openid', 'email'],
clientId: 'NPSfOkH5eZrTy8PMDlvx',
urls: {
issuer: 'https://auth-js-test.okta.com/oauth2/aus8aus76q8iphupD0h7',
authorizeUrl: 'https://auth-js-test.okta.com/oauth2/aus8aus76q8iphupD0h7/v1/authorize',
Expand Down Expand Up @@ -1202,6 +1253,7 @@ define(function(require) {
state: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
nonce: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
scopes: ['openid', 'email'],
clientId: 'NPSfOkH5eZrTy8PMDlvx',
urls: {
issuer: 'https://auth-js-test.okta.com',
authorizeUrl: 'https://auth-js-test.okta.com/oauth2/v1/authorize',
Expand Down Expand Up @@ -1240,6 +1292,7 @@ define(function(require) {
state: oauthUtil.mockedState,
nonce: oauthUtil.mockedNonce,
scopes: ['openid', 'email'],
clientId: 'NPSfOkH5eZrTy8PMDlvx',
urls: {
issuer: 'https://auth-js-test.okta.com/oauth2/aus8aus76q8iphupD0h7',
authorizeUrl: 'https://auth-js-test.okta.com/oauth2/aus8aus76q8iphupD0h7/v1/authorize',
Expand Down Expand Up @@ -1274,6 +1327,7 @@ define(function(require) {
state: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
nonce: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
scopes: ['openid', 'email'],
clientId: 'NPSfOkH5eZrTy8PMDlvx',
urls: {
issuer: 'https://auth-js-test.okta.com',
authorizeUrl: 'https://auth-js-test.okta.com/oauth2/v1/authorize',
Expand Down Expand Up @@ -1308,6 +1362,7 @@ define(function(require) {
state: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
nonce: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
scopes: ['openid', 'email'],
clientId: 'NPSfOkH5eZrTy8PMDlvx',
urls: {
issuer: 'https://auth-js-test.okta.com',
authorizeUrl: 'https://auth-js-test.okta.com/oauth2/v1/authorize',
Expand Down Expand Up @@ -1342,6 +1397,7 @@ define(function(require) {
state: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
nonce: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
scopes: ['openid', 'email'],
clientId: 'NPSfOkH5eZrTy8PMDlvx',
urls: {
issuer: 'https://auth-js-test.okta.com',
authorizeUrl: 'https://auth-js-test.okta.com/oauth2/v1/authorize',
Expand Down Expand Up @@ -2077,11 +2133,18 @@ define(function(require) {
});

describe('token.verify', function() {
var validationParams = {
clientId: tokens.standardIdTokenParsed.clientId,
issuer: tokens.standardIdTokenParsed.issuer
};

it('verifies a valid idToken with nonce', function(done) {
var client = setupSync();
util.warpToUnixTime(1449699929);
oauthUtil.loadWellKnownAndKeysCache();
client.token.verify(tokens.standardIdTokenParsed, oauthUtil.mockedNonce)
var alteredParams = _.clone(validationParams);
alteredParams.nonce = tokens.standardIdTokenParsed.nonce;
client.token.verify(tokens.standardIdTokenParsed, validationParams)
.then(function(res) {
expect(res).toEqual(tokens.standardIdTokenParsed);
})
Expand All @@ -2094,7 +2157,7 @@ define(function(require) {
var client = setupSync();
util.warpToUnixTime(1449699929);
oauthUtil.loadWellKnownAndKeysCache();
client.token.verify(tokens.standardIdTokenParsed)
client.token.verify(tokens.standardIdTokenParsed, validationParams)
.then(function(res) {
expect(res).toEqual(tokens.standardIdTokenParsed);
})
Expand Down Expand Up @@ -2124,37 +2187,39 @@ define(function(require) {
});
it('issued in the future', function(done) {
util.warpToDistantPast();
expectError([tokens.standardIdTokenParsed],
expectError([tokens.standardIdTokenParsed, validationParams],
'The JWT was issued in the future')
.fin(done);
});
it('expired', function(done) {
util.warpToDistantFuture();
expectError([tokens.standardIdTokenParsed],
expectError([tokens.standardIdTokenParsed, validationParams],
'The JWT expired and is no longer valid')
.fin(done);
});
it('invalid nonce', function(done) {
expectError([tokens.standardIdTokenParsed, 'invalidNonce'],
var alteredParams = _.clone(validationParams);
alteredParams.nonce = 'invalidNonce';
expectError([tokens.standardIdToken2Parsed, alteredParams],
'OAuth flow response nonce doesn\'t match request nonce')
.fin(done);
});
it('invalid audience', function(done) {
var idToken = _.clone(tokens.standardIdTokenParsed);
idToken.clientId = 'invalidAudience';
expectError([idToken],
var alteredParams = _.clone(validationParams);
alteredParams.clientId = 'invalidAudience';
expectError([tokens.standardIdTokenParsed, alteredParams],
'The audience [NPSfOkH5eZrTy8PMDlvx] does not match [invalidAudience]')
.fin(done);
});
it('invalid issuer', function(done) {
var idToken = _.clone(tokens.standardIdTokenParsed);
idToken.issuer = 'http://invalidissuer.example.com';
expectError([idToken],
var alteredParams = _.clone(validationParams);
alteredParams.issuer = 'http://invalidissuer.example.com';
expectError([tokens.standardIdTokenParsed, alteredParams],
'The issuer [https://auth-js-test.okta.com] does not match [http://invalidissuer.example.com]')
.fin(done);
});
it('expired before issued', function(done) {
expectError([tokens.expiredBeforeIssuedIdTokenParsed],
expectError([tokens.expiredBeforeIssuedIdTokenParsed, validationParams],
'The JWT expired before it was issued')
.fin(done);
});
Expand Down
11 changes: 8 additions & 3 deletions test/util/oauthUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,13 @@ define(function(require) {

var authClient;
if (opts.oktaAuthArgs) {
// Disable token validation for all tests
opts.oktaAuthArgs.ignoreSignature = true;
authClient = new OktaAuth(opts.oktaAuthArgs);
} else {
authClient = new OktaAuth({
url: 'https://auth-js-test.okta.com'
url: 'https://auth-js-test.okta.com',
ignoreSignature: true
});
}

Expand Down Expand Up @@ -329,7 +332,8 @@ define(function(require) {
var client = new OktaAuth(opts.oktaAuthArgs || {
url: 'https://auth-js-test.okta.com',
clientId: 'NPSfOkH5eZrTy8PMDlvx',
redirectUri: 'https://example.com/redirect'
redirectUri: 'https://example.com/redirect',
ignoreSignature: true
});

oauthUtil.mockStateAndNonce();
Expand Down Expand Up @@ -422,7 +426,8 @@ define(function(require) {
var client = new OktaAuth({
url: 'https://auth-js-test.okta.com',
clientId: 'NPSfOkH5eZrTy8PMDlvx',
redirectUri: 'https://example.com/redirect'
redirectUri: 'https://example.com/redirect',
ignoreSignature: true
});

var emitter = new EventEmitter();
Expand Down

0 comments on commit 825f307

Please sign in to comment.