177 lines
5.0 KiB
JavaScript
177 lines
5.0 KiB
JavaScript
|
"use strict";
|
||
|
|
||
|
// Possible User Errors
|
||
|
|
||
|
/**
|
||
|
* @typedef AuthError
|
||
|
* @property {string} message
|
||
|
* @property {number} status
|
||
|
* @property {string} code
|
||
|
* @property {any} [details]
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @param {string} msg
|
||
|
* @param {{
|
||
|
* status: number,
|
||
|
* code: string,
|
||
|
* details?: any,
|
||
|
* }} opts
|
||
|
* @returns {AuthError}
|
||
|
*/
|
||
|
function create(msg, { status = 401, code = "", details }) {
|
||
|
/** @type AuthError */
|
||
|
//@ts-ignore
|
||
|
var err = new Error(msg);
|
||
|
err.message = err.message;
|
||
|
err.status = status;
|
||
|
err.code = code;
|
||
|
if (details) {
|
||
|
err.details = details;
|
||
|
}
|
||
|
err.source = "keyfetch";
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
// DEVELOPER_ERROR - a good token won't make a difference
|
||
|
var E_DEVELOPER = "DEVELOPER_ERROR";
|
||
|
|
||
|
// BAD_GATEWAY - there may be a temporary error fetching the public or or whatever
|
||
|
var E_BAD_GATEWAY = "BAD_GATEWAY";
|
||
|
|
||
|
// MALFORMED_TOKEN - the token could not be verified - not parsable, missing claims, etc
|
||
|
var E_MALFORMED = "MALFORMED_JWT";
|
||
|
|
||
|
// INVALID_TOKEN - the token's properties don't meet requirements - iss, claims, sig, exp
|
||
|
var E_INVALID = "INVALID_JWT";
|
||
|
|
||
|
module.exports = {
|
||
|
//
|
||
|
// DEVELOPER_ERROR (dev / server)
|
||
|
//
|
||
|
|
||
|
/**
|
||
|
* @param {string} msg
|
||
|
* @returns {AuthError}
|
||
|
*/
|
||
|
DEVELOPER_ERROR: function (msg) {
|
||
|
return create(msg, { status: 500, code: E_DEVELOPER });
|
||
|
},
|
||
|
BAD_GATEWAY: function (/*err*/) {
|
||
|
var msg = "The server encountered a network error or a bad gateway.";
|
||
|
return create(msg, { status: 502, code: E_BAD_GATEWAY });
|
||
|
},
|
||
|
|
||
|
//
|
||
|
// MALFORMED_TOKEN (dev / client)
|
||
|
//
|
||
|
|
||
|
/**
|
||
|
* @param {string} iss
|
||
|
* @returns {AuthError}
|
||
|
*/
|
||
|
INSECURE_ISSUER: function (iss) {
|
||
|
var msg =
|
||
|
"'" + iss + "' is NOT secure. Set env 'KEYFETCH_ALLOW_INSECURE_HTTP=true' to allow for testing. (iss)";
|
||
|
return create(msg, { status: 400, code: E_MALFORMED });
|
||
|
},
|
||
|
/**
|
||
|
* @param {string} jwt
|
||
|
* @returns {AuthError}
|
||
|
*/
|
||
|
TOKEN_PARSE_ERROR: function (jwt) {
|
||
|
var msg = "could not parse jwt: '" + jwt + "'";
|
||
|
return create(msg, { status: 400, code: E_MALFORMED });
|
||
|
},
|
||
|
/**
|
||
|
* @param {string} iss
|
||
|
* @returns {AuthError}
|
||
|
*/
|
||
|
TOKEN_NO_ISSUER: function (iss) {
|
||
|
var msg = "'iss' is not defined";
|
||
|
return create(msg, { status: 400, code: E_MALFORMED });
|
||
|
},
|
||
|
|
||
|
//
|
||
|
// INVALID_TOKEN (dev / client)
|
||
|
//
|
||
|
|
||
|
/**
|
||
|
* @param {number} exp
|
||
|
* @returns {AuthError}
|
||
|
*/
|
||
|
TOKEN_EXPIRED: function (exp) {
|
||
|
//var msg = "The auth token is expired. (exp='" + exp + "')";
|
||
|
var msg = "token's 'exp' has passed or could not parsed: '" + exp + "'";
|
||
|
return create(msg, { code: E_INVALID });
|
||
|
},
|
||
|
/**
|
||
|
* @param {number} nbf
|
||
|
* @returns {AuthError}
|
||
|
*/
|
||
|
TOKEN_INACTIVE: function (nbf) {
|
||
|
//var msg = "The auth token is not active yet. (nbf='" + nbf + "')";
|
||
|
var msg = "token's 'nbf' has not been reached or could not parsed: '" + nbf + "'";
|
||
|
return create(msg, { code: E_INVALID });
|
||
|
},
|
||
|
/** @returns {AuthError} */
|
||
|
TOKEN_INVALID_SIGNATURE: function () {
|
||
|
//var msg = "The auth token is not properly signed and could not be verified.";
|
||
|
var msg = "token signature verification was unsuccessful";
|
||
|
return create(msg, { code: E_INVALID });
|
||
|
},
|
||
|
/** @returns {AuthError} */
|
||
|
TOKEN_UNKNOWN_SIGNER: function () {
|
||
|
var msg = "Retrieved a list of keys, but none of them matched the 'kid' (key id) of the token.";
|
||
|
return create(msg, { code: E_INVALID });
|
||
|
},
|
||
|
/**
|
||
|
* @param {string} id
|
||
|
* @returns {AuthError}
|
||
|
*/
|
||
|
JWK_NOT_FOUND: function (id) {
|
||
|
var msg = "No JWK found by kid or thumbprint '" + id + "'";
|
||
|
return create(msg, { code: E_INVALID });
|
||
|
},
|
||
|
/** @returns {AuthError} */
|
||
|
OIDC_CONFIG_NOT_FOUND: function () {
|
||
|
//var msg = "Failed to retrieve OpenID configuration for token issuer";
|
||
|
var msg = "Failed to retrieve openid configuration";
|
||
|
return create(msg, { code: E_INVALID });
|
||
|
},
|
||
|
/**
|
||
|
* @param {string} iss
|
||
|
* @returns {AuthError}
|
||
|
*/
|
||
|
ISSUER_NOT_TRUSTED: function (iss) {
|
||
|
var msg = "token was issued by an untrusted issuer: '" + iss + "'";
|
||
|
return create(msg, { code: E_INVALID });
|
||
|
},
|
||
|
/**
|
||
|
* @param {Array<string>} claimNames
|
||
|
* @returns {AuthError}
|
||
|
*/
|
||
|
CLAIMS_MISMATCH: function (claimNames) {
|
||
|
var msg = "token did not match on one or more authorization claims: '" + claimNames + "'";
|
||
|
return create(msg, { code: E_INVALID });
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// for README
|
||
|
if (require.main === module) {
|
||
|
console.info("| Name | Status | Message (truncated) |");
|
||
|
console.info("| ---- | ------ | ------------------- |");
|
||
|
Object.keys(module.exports).forEach(function (k) {
|
||
|
//@ts-ignore
|
||
|
var E = module.exports[k];
|
||
|
var e = E();
|
||
|
var code = e.code;
|
||
|
var msg = e.message;
|
||
|
if ("E_" + k !== e.code) {
|
||
|
code = k;
|
||
|
msg = e.details || msg;
|
||
|
}
|
||
|
console.info(`| ${code} | ${e.status} | ${msg.slice(0, 45)}... |`);
|
||
|
});
|
||
|
}
|