@jmondi/oauth2-server
Advanced tools
Comparing version 0.2.0-beta.0 to 0.2.0-beta.1
@@ -1,12 +0,2 @@ | ||
(function webpackUniversalModuleDefinition(root, factory) { | ||
if(typeof exports === 'object' && typeof module === 'object') | ||
module.exports = factory(); | ||
else if(typeof define === 'function' && define.amd) | ||
define([], factory); | ||
else if(typeof exports === 'object') | ||
exports["@jmondi/oauth2-server"] = factory(); | ||
else | ||
root["@jmondi/oauth2-server"] = factory(); | ||
})(global, function() { | ||
return /******/ (function(modules) { // webpackBootstrap | ||
/******/ (function(modules) { // webpackBootstrap | ||
/******/ // The module cache | ||
@@ -91,337 +81,5 @@ /******/ var installedModules = {}; | ||
/******/ __webpack_require__.p = ""; | ||
/******/ | ||
/******/ | ||
/******/ // Load entry module and return exports | ||
/******/ return __webpack_require__(__webpack_require__.s = 1); | ||
/******/ }) | ||
/************************************************************************/ | ||
/******/ ([ | ||
/* 0 */ | ||
/***/ (function(module, exports) { | ||
/** | ||
* Helpers. | ||
*/ | ||
var s = 1000; | ||
var m = s * 60; | ||
var h = m * 60; | ||
var d = h * 24; | ||
var w = d * 7; | ||
var y = d * 365.25; | ||
/** | ||
* Parse or format the given `val`. | ||
* | ||
* Options: | ||
* | ||
* - `long` verbose formatting [false] | ||
* | ||
* @param {String|Number} val | ||
* @param {Object} [options] | ||
* @throws {Error} throw an error if val is not a non-empty string or a number | ||
* @return {String|Number} | ||
* @api public | ||
*/ | ||
module.exports = function(val, options) { | ||
options = options || {}; | ||
var type = typeof val; | ||
if (type === 'string' && val.length > 0) { | ||
return parse(val); | ||
} else if (type === 'number' && isFinite(val)) { | ||
return options.long ? fmtLong(val) : fmtShort(val); | ||
} | ||
throw new Error( | ||
'val is not a non-empty string or a valid number. val=' + | ||
JSON.stringify(val) | ||
); | ||
}; | ||
/** | ||
* Parse the given `str` and return milliseconds. | ||
* | ||
* @param {String} str | ||
* @return {Number} | ||
* @api private | ||
*/ | ||
function parse(str) { | ||
str = String(str); | ||
if (str.length > 100) { | ||
return; | ||
} | ||
var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec( | ||
str | ||
); | ||
if (!match) { | ||
return; | ||
} | ||
var n = parseFloat(match[1]); | ||
var type = (match[2] || 'ms').toLowerCase(); | ||
switch (type) { | ||
case 'years': | ||
case 'year': | ||
case 'yrs': | ||
case 'yr': | ||
case 'y': | ||
return n * y; | ||
case 'weeks': | ||
case 'week': | ||
case 'w': | ||
return n * w; | ||
case 'days': | ||
case 'day': | ||
case 'd': | ||
return n * d; | ||
case 'hours': | ||
case 'hour': | ||
case 'hrs': | ||
case 'hr': | ||
case 'h': | ||
return n * h; | ||
case 'minutes': | ||
case 'minute': | ||
case 'mins': | ||
case 'min': | ||
case 'm': | ||
return n * m; | ||
case 'seconds': | ||
case 'second': | ||
case 'secs': | ||
case 'sec': | ||
case 's': | ||
return n * s; | ||
case 'milliseconds': | ||
case 'millisecond': | ||
case 'msecs': | ||
case 'msec': | ||
case 'ms': | ||
return n; | ||
default: | ||
return undefined; | ||
} | ||
} | ||
/** | ||
* Short format for `ms`. | ||
* | ||
* @param {Number} ms | ||
* @return {String} | ||
* @api private | ||
*/ | ||
function fmtShort(ms) { | ||
var msAbs = Math.abs(ms); | ||
if (msAbs >= d) { | ||
return Math.round(ms / d) + 'd'; | ||
} | ||
if (msAbs >= h) { | ||
return Math.round(ms / h) + 'h'; | ||
} | ||
if (msAbs >= m) { | ||
return Math.round(ms / m) + 'm'; | ||
} | ||
if (msAbs >= s) { | ||
return Math.round(ms / s) + 's'; | ||
} | ||
return ms + 'ms'; | ||
} | ||
/** | ||
* Long format for `ms`. | ||
* | ||
* @param {Number} ms | ||
* @return {String} | ||
* @api private | ||
*/ | ||
function fmtLong(ms) { | ||
var msAbs = Math.abs(ms); | ||
if (msAbs >= d) { | ||
return plural(ms, msAbs, d, 'day'); | ||
} | ||
if (msAbs >= h) { | ||
return plural(ms, msAbs, h, 'hour'); | ||
} | ||
if (msAbs >= m) { | ||
return plural(ms, msAbs, m, 'minute'); | ||
} | ||
if (msAbs >= s) { | ||
return plural(ms, msAbs, s, 'second'); | ||
} | ||
return ms + ' ms'; | ||
} | ||
/** | ||
* Pluralization helper. | ||
*/ | ||
function plural(ms, msAbs, n, name) { | ||
var isPlural = msAbs >= n * 1.5; | ||
return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : ''); | ||
} | ||
/***/ }), | ||
/* 1 */ | ||
/***/ (function(module, __webpack_exports__, __webpack_require__) { | ||
"use strict"; | ||
// ESM COMPAT FLAG | ||
__webpack_require__.r(__webpack_exports__); | ||
// EXPORTS | ||
__webpack_require__.d(__webpack_exports__, "DateInterval", function() { return /* reexport */ authorization_server_DateInterval; }); | ||
__webpack_require__.d(__webpack_exports__, "AuthorizationServer", function() { return /* reexport */ authorization_server_AuthorizationServer; }); | ||
// EXTERNAL MODULE: ./node_modules/ms/index.js | ||
var ms = __webpack_require__(0); | ||
var ms_default = /*#__PURE__*/__webpack_require__.n(ms); | ||
// CONCATENATED MODULE: ./src/exceptions/oauth.exception.ts | ||
const HttpStatus = { | ||
NOT_ACCEPTABLE: 406, | ||
BAD_REQUEST: 400, | ||
UNAUTHORIZED: 401, | ||
INTERNAL_SERVER_ERROR: 500, | ||
OK: 200, | ||
}; | ||
var ErrorType; | ||
(function (ErrorType) { | ||
ErrorType["InvalidRequest"] = "invalid_request"; | ||
ErrorType["InvalidClient"] = "invalid_client"; | ||
ErrorType["InvalidGrant"] = "invalid_grant"; | ||
ErrorType["InvalidScope"] = "invalid_scope"; | ||
ErrorType["UnauthorizedClient"] = "unauthorized_client"; | ||
ErrorType["UnsupportedGrantType"] = "unsupported_grant_type"; | ||
ErrorType["AccessDenied"] = "access_denied"; | ||
})(ErrorType || (ErrorType = {})); | ||
class OAuthException extends Error { | ||
constructor(error, errorType, errorDescription, errorUri, status = HttpStatus.BAD_REQUEST) { | ||
super(errorDescription ? `${error}: ${errorDescription}` : error); | ||
this.error = error; | ||
this.errorType = errorType; | ||
this.errorDescription = errorDescription; | ||
this.errorUri = errorUri; | ||
this.status = status; | ||
Error.captureStackTrace(this, this.constructor); | ||
this.name = this.constructor.name; | ||
} | ||
static invalidRequest(parameter, errorDescription) { | ||
let message = "The request is missing a required parameter, includes an invalid parameter value, "; | ||
message += "includes a parameter more than once, or is otherwise malformed"; | ||
errorDescription = errorDescription ? errorDescription : `Check the \`${parameter}\` parameter`; | ||
return new OAuthException(message, ErrorType.InvalidRequest, errorDescription); | ||
} | ||
static invalidClient(errorDescription) { | ||
return new OAuthException("Client authentication failed", ErrorType.InvalidClient, errorDescription, undefined, HttpStatus.UNAUTHORIZED); | ||
} | ||
static invalidGrant(errorDescription) { | ||
let message = "The provided authorization grant (e.g., authorization_code, client_credentials) or refresh token "; | ||
message += | ||
"is invalid, expired, revoked, or does not match the redirection URI used in the authorization request, "; | ||
message += "or was issued to another client"; | ||
return new OAuthException(message, ErrorType.InvalidGrant, errorDescription); | ||
} | ||
static invalidScope(scope, redirectUri) { | ||
const message = "The requested scope is invalid, unknown, or malformed"; | ||
let hint = "Specify a scope in the request or set a default scope"; | ||
if (scope) { | ||
hint = `Check the \`${scope}\` scope(s)`; | ||
} | ||
return new OAuthException(message, ErrorType.InvalidScope, hint, redirectUri); | ||
} | ||
static unauthorizedClient() { | ||
return new OAuthException(`unauthorized client`, ErrorType.UnauthorizedClient); | ||
} | ||
static unsupportedGrantType() { | ||
return new OAuthException("unsupported grant_type", ErrorType.UnsupportedGrantType); | ||
} | ||
static logicException(message) { | ||
return new OAuthException(message, ErrorType.InvalidRequest); | ||
} | ||
static accessDenied(errorDescription) { | ||
return new OAuthException("The resource owner or authorization server denied the request", ErrorType.AccessDenied, errorDescription, undefined, HttpStatus.UNAUTHORIZED); | ||
} | ||
} | ||
// CONCATENATED MODULE: ./src/authorization_server.ts | ||
var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
class authorization_server_DateInterval { | ||
constructor(interval) { | ||
this.interval = interval; | ||
this.init = Date.now(); | ||
this.ms = ms_default()(interval); | ||
} | ||
getEndDate() { | ||
return new Date(this.getEndTimeMs()); | ||
} | ||
getEndTimeMs() { | ||
return this.init + this.ms; | ||
} | ||
getEndTimeSeconds() { | ||
return Math.ceil(this.getEndTimeMs() / 1000); | ||
} | ||
getSeconds() { | ||
return Math.ceil(this.ms / 1000); | ||
} | ||
static getDateEnd(ms) { | ||
return new authorization_server_DateInterval(ms).getEndDate(); | ||
} | ||
} | ||
class authorization_server_AuthorizationServer { | ||
constructor() { | ||
this.enabledGrantTypes = {}; | ||
this.grantTypeAccessTokenTTL = {}; | ||
} | ||
enableGrantType(grantType, accessTokenTTL) { | ||
if (!accessTokenTTL) | ||
accessTokenTTL = new authorization_server_DateInterval("1h"); | ||
this.enabledGrantTypes[grantType.identifier] = grantType; | ||
this.grantTypeAccessTokenTTL[grantType.identifier] = accessTokenTTL; | ||
} | ||
respondToAccessTokenRequest(req, res) { | ||
for (const grantType of Object.values(this.enabledGrantTypes)) { | ||
if (!grantType.canRespondToAccessTokenRequest(req)) { | ||
continue; | ||
} | ||
const accessTokenTTL = this.grantTypeAccessTokenTTL[grantType.identifier]; | ||
return grantType.respondToAccessTokenRequest(req, res, accessTokenTTL); | ||
} | ||
throw OAuthException.unsupportedGrantType(); | ||
} | ||
validateAuthorizationRequest(req) { | ||
for (const grantType of Object.values(this.enabledGrantTypes)) { | ||
if (grantType.canRespondToAuthorizationRequest(req)) { | ||
return grantType.validateAuthorizationRequest(req); | ||
} | ||
} | ||
throw OAuthException.unsupportedGrantType(); | ||
} | ||
completeAuthorizationRequest(authorizationRequest) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const grant = this.enabledGrantTypes[authorizationRequest.grantTypeId]; | ||
return yield grant.completeAuthorizationRequest(authorizationRequest); | ||
}); | ||
} | ||
} | ||
// CONCATENATED MODULE: ./src/index.ts | ||
/***/ }) | ||
/******/ ]); | ||
}); | ||
/******/ ([]); | ||
//# sourceMappingURL=jmondi-oauth2-server.js.map |
{ | ||
"version": "0.2.0-beta.0", | ||
"version": "0.2.0-beta.1", | ||
"license": "MIT", | ||
"name": "@jmondi/oauth2-server", | ||
"author": "Jason Raimondi", | ||
"module": "dist/jmondi-oauth2-server.js", | ||
"module": "src/index.ts", | ||
"main": "dist/jmondi-oauth2-server.js", | ||
@@ -20,3 +20,2 @@ "typings": "dist/index.d.ts", | ||
"build:prod": "cross-env NODE_ENV=production TS_NODE_PROJECT=tsconfig.webpack.json webpack --config webpack.config.ts", | ||
"start": "rollup -c rollup.config.ts -w", | ||
"format": "prettier --write \"{src,test,examples}/**/*.(t|j)s*\"", | ||
@@ -23,0 +22,0 @@ "lint": "eslint \"{src,test}/**/*.ts\" --fix", |
@@ -9,4 +9,6 @@ # @jmondi/oauth2-server | ||
`@jmondi/oauth2-server` is a standards compliant implementation of an OAuth 2.0 authorization server, written in TypeScript. | ||
`@jmondi/oauth2-server` is a standards compliant implementation of an OAuth 2.0 authorization server for Node, written in TypeScript. | ||
Requires `node >= 12` | ||
Out of the box it supports the following grants: | ||
@@ -27,3 +29,11 @@ | ||
## @TODO | ||
:construction_worker: This project is under development :construction: | ||
* fix: output structure being uploaded to npm | ||
* feat: flag for require code_challenge for public clients | ||
* feat: token introspection | ||
* chore: documentation | ||
## Installing | ||
@@ -37,2 +47,13 @@ | ||
about entity interfaces | ||
about repository interfaces | ||
then authorization server | ||
then enable grants | ||
// this should go last as example implemenations | ||
See the [In Memory example that uses Express](./examples/in_memory) | ||
@@ -60,3 +81,3 @@ | ||
The `/token` endpoint is a back channel endpoint that issues an a useable access token. | ||
The `/token` endpoint is a back channel endpoint that issues a useable access token. | ||
@@ -299,10 +320,2 @@ ```typescript | ||
## @TODO | ||
:construction_worker: This project is under development :construction: | ||
* feat: flag for require code_challenge for public clients | ||
* feat: token introspection | ||
* chore: documentation | ||
## Sources | ||
@@ -309,0 +322,0 @@ |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
116441
73
339
1923