all files / express-stormpath/lib/okta/ access-token-authenticator.js

78.57% Statements 33/42
57.14% Branches 8/14
77.78% Functions 7/9
78.05% Lines 32/41
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99                                17×     17× 17×     17× 17×     17× 17×                                                                                          
'use strict';
 
var jwkToPem = require('jwk-to-pem');
var nJwt = require('njwt');
var requestExecutor = require('./request-executor');
var StormpathAccessTokenAuthenticationResult = require('stormpath/lib/oauth/stormpath-access-token-authentication-result');
 
/**
 * @class
 *
 * @constructor
 *
 * @description
 *
 * Creates an authenticator that can be used to validate access tokens that have
 * been issued by an Okta Authorization Sever
 *
 * @returns {Jwt}
 */
 
function AccessTokenAuthenticator(client) {
  Iif (!(this instanceof AccessTokenAuthenticator)) {
    return new AccessTokenAuthenticator();
  }
  this.client = client;
  this.localValidation = false;
}
 
AccessTokenAuthenticator.prototype.withLocalValidation = function withLocalValidation() {
  this.localValidation = true;
  return this;
};
 
AccessTokenAuthenticator.prototype.forIssuer = function forIssuer(issuer) {
  this.expectedIssuer = issuer;
  return this;
};
 
AccessTokenAuthenticator.prototype.forOrg = function forOrg(org) {
  this.org = org;
  return this;
};
 
AccessTokenAuthenticator.prototype.withClientId = function withClientId(clientId) {
  this.clientId = clientId;
  return this;
};
 
AccessTokenAuthenticator.prototype.authenticate = function authenticate(jwtAccessTokenString, callback) {
  var self = this;
 
  var verifier = nJwt.createVerifier()
    .withKeyResolver(this.jwksResolver.bind(this))
    .setSigningAlgorithm('RS256');
 
  verifier.verify(jwtAccessTokenString, function (err, jwt) {
    Iif (err) {
      return callback(err);
    }
 
    Eif (self.localValidation) {
      return callback(err, new StormpathAccessTokenAuthenticationResult(self.client, {
        jwt: jwtAccessTokenString,
        expandedJwt: jwt,
        account: {
          href: 'users/' + jwt.body.uid
        }
      }));
    }
 
  });
};
 
AccessTokenAuthenticator.prototype.jwksResolver = function jwksResolver(kid, callback) {
  var req = {
    url: this.expectedIssuer + '/v1/keys',
    json: true
  };
  requestExecutor(req, function (err, res) {
    Iif (err) {
      return callback(err);
    }
    Iif (!res.keys || !res.keys.length) {
      return callback('Keys collection not found');
    }
 
    var matches = res.keys.filter((key) => key.kid === kid);
 
    Iif (matches.length === 0) {
      return callback('Unresolved signing key');
    }
 
    callback(null, jwkToPem(matches[0]));
 
  });
};
 
module.exports = AccessTokenAuthenticator;