angular2-jwt
Version:
Helper library for handling JWTs in Angular 2+
362 lines • 13.9 kB
JavaScript
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
var http_1 = require("@angular/http");
var core_1 = require("@angular/core");
var Observable_1 = require("rxjs/Observable");
require("rxjs/add/observable/fromPromise");
require("rxjs/add/observable/defer");
require("rxjs/add/operator/mergeMap");
var AuthConfigConsts = (function () {
function AuthConfigConsts() {
}
return AuthConfigConsts;
}());
AuthConfigConsts.DEFAULT_TOKEN_NAME = 'token';
AuthConfigConsts.DEFAULT_HEADER_NAME = 'Authorization';
AuthConfigConsts.HEADER_PREFIX_BEARER = 'Bearer ';
exports.AuthConfigConsts = AuthConfigConsts;
var AuthConfigDefaults = {
headerName: AuthConfigConsts.DEFAULT_HEADER_NAME,
headerPrefix: null,
tokenName: AuthConfigConsts.DEFAULT_TOKEN_NAME,
tokenGetter: function () { return localStorage.getItem(AuthConfigDefaults.tokenName); },
noJwtError: false,
noClientCheck: false,
globalHeaders: [],
noTokenScheme: false
};
/**
* Sets up the authentication configuration.
*/
var AuthConfig = (function () {
function AuthConfig(config) {
config = config || {};
this._config = objectAssign({}, AuthConfigDefaults, config);
if (this._config.headerPrefix) {
this._config.headerPrefix += ' ';
}
else if (this._config.noTokenScheme) {
this._config.headerPrefix = '';
}
else {
this._config.headerPrefix = AuthConfigConsts.HEADER_PREFIX_BEARER;
}
if (config.tokenName && !config.tokenGetter) {
this._config.tokenGetter = function () { return localStorage.getItem(config.tokenName); };
}
}
AuthConfig.prototype.getConfig = function () {
return this._config;
};
return AuthConfig;
}());
exports.AuthConfig = AuthConfig;
var AuthHttpError = (function (_super) {
__extends(AuthHttpError, _super);
function AuthHttpError() {
return _super !== null && _super.apply(this, arguments) || this;
}
return AuthHttpError;
}(Error));
exports.AuthHttpError = AuthHttpError;
/**
* Allows for explicit authenticated HTTP requests.
*/
var AuthHttp = (function () {
function AuthHttp(options, http, defOpts) {
var _this = this;
this.http = http;
this.defOpts = defOpts;
this.config = options.getConfig();
this.tokenStream = new Observable_1.Observable(function (obs) {
obs.next(_this.config.tokenGetter());
});
}
AuthHttp.prototype.mergeOptions = function (providedOpts, defaultOpts) {
var newOptions = defaultOpts || new http_1.RequestOptions();
if (this.config.globalHeaders) {
this.setGlobalHeaders(this.config.globalHeaders, providedOpts);
}
newOptions = newOptions.merge(new http_1.RequestOptions(providedOpts));
return newOptions;
};
AuthHttp.prototype.requestHelper = function (requestArgs, additionalOptions) {
var options = new http_1.RequestOptions(requestArgs);
if (additionalOptions) {
options = options.merge(additionalOptions);
}
return this.request(new http_1.Request(this.mergeOptions(options, this.defOpts)));
};
AuthHttp.prototype.requestWithToken = function (req, token) {
if (!this.config.noClientCheck && !tokenNotExpired(undefined, token)) {
if (!this.config.noJwtError) {
return new Observable_1.Observable(function (obs) {
obs.error(new AuthHttpError('No JWT present or has expired'));
});
}
}
else {
req.headers.set(this.config.headerName, this.config.headerPrefix + token);
}
return this.http.request(req);
};
AuthHttp.prototype.setGlobalHeaders = function (headers, request) {
if (!request.headers) {
request.headers = new http_1.Headers();
}
headers.forEach(function (header) {
var key = Object.keys(header)[0];
var headerValue = header[key];
request.headers.set(key, headerValue);
});
};
AuthHttp.prototype.request = function (url, options) {
var _this = this;
if (typeof url === 'string') {
return this.get(url, options); // Recursion: transform url from String to Request
}
// else if ( ! url instanceof Request ) {
// throw new Error('First argument must be a url string or Request instance.');
// }
// from this point url is always an instance of Request;
var req = url;
// Create a cold observable and load the token just in time
return Observable_1.Observable.defer(function () {
var token = _this.config.tokenGetter();
if (token instanceof Promise) {
return Observable_1.Observable.fromPromise(token).mergeMap(function (jwtToken) { return _this.requestWithToken(req, jwtToken); });
}
else {
return _this.requestWithToken(req, token);
}
});
};
AuthHttp.prototype.get = function (url, options) {
return this.requestHelper({ body: '', method: http_1.RequestMethod.Get, url: url }, options);
};
AuthHttp.prototype.post = function (url, body, options) {
return this.requestHelper({ body: body, method: http_1.RequestMethod.Post, url: url }, options);
};
AuthHttp.prototype.put = function (url, body, options) {
return this.requestHelper({ body: body, method: http_1.RequestMethod.Put, url: url }, options);
};
AuthHttp.prototype.delete = function (url, options) {
return this.requestHelper({ body: '', method: http_1.RequestMethod.Delete, url: url }, options);
};
AuthHttp.prototype.patch = function (url, body, options) {
return this.requestHelper({ body: body, method: http_1.RequestMethod.Patch, url: url }, options);
};
AuthHttp.prototype.head = function (url, options) {
return this.requestHelper({ body: '', method: http_1.RequestMethod.Head, url: url }, options);
};
AuthHttp.prototype.options = function (url, options) {
return this.requestHelper({ body: '', method: http_1.RequestMethod.Options, url: url }, options);
};
return AuthHttp;
}());
AuthHttp = __decorate([
core_1.Injectable(),
__metadata("design:paramtypes", [AuthConfig, http_1.Http, http_1.RequestOptions])
], AuthHttp);
exports.AuthHttp = AuthHttp;
/**
* Helper class to decode and find JWT expiration.
*/
var JwtHelper = (function () {
function JwtHelper() {
}
JwtHelper.prototype.urlBase64Decode = function (str) {
var output = str.replace(/-/g, '+').replace(/_/g, '/');
switch (output.length % 4) {
case 0: {
break;
}
case 2: {
output += '==';
break;
}
case 3: {
output += '=';
break;
}
default: {
throw 'Illegal base64url string!';
}
}
return this.b64DecodeUnicode(output);
};
// credits for decoder goes to https://github.com/atk
JwtHelper.prototype.b64decode = function (str) {
var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
var output = '';
str = String(str).replace(/=+$/, '');
if (str.length % 4 == 1) {
throw new Error("'atob' failed: The string to be decoded is not correctly encoded.");
}
for (
// initialize result and counters
var bc = 0, bs = void 0, buffer = void 0, idx = 0;
// get next character
buffer = str.charAt(idx++);
// character found in table? initialize bit storage and add its ascii value;
~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer,
// and if not first of each 4 characters,
// convert the first 8 bits to one ascii character
bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0) {
// try to find character in table (0-63, not found => -1)
buffer = chars.indexOf(buffer);
}
return output;
};
// https://developer.mozilla.org/en/docs/Web/API/WindowBase64/Base64_encoding_and_decoding#The_Unicode_Problem
JwtHelper.prototype.b64DecodeUnicode = function (str) {
return decodeURIComponent(Array.prototype.map.call(this.b64decode(str), function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
};
JwtHelper.prototype.decodeToken = function (token) {
var parts = token.split('.');
if (parts.length !== 3) {
throw new Error('JWT must have 3 parts');
}
var decoded = this.urlBase64Decode(parts[1]);
if (!decoded) {
throw new Error('Cannot decode the token');
}
return JSON.parse(decoded);
};
JwtHelper.prototype.getTokenExpirationDate = function (token) {
var decoded;
decoded = this.decodeToken(token);
if (!decoded.hasOwnProperty('exp')) {
return null;
}
var date = new Date(0); // The 0 here is the key, which sets the date to the epoch
date.setUTCSeconds(decoded.exp);
return date;
};
JwtHelper.prototype.isTokenExpired = function (token, offsetSeconds) {
var date = this.getTokenExpirationDate(token);
offsetSeconds = offsetSeconds || 0;
if (date == null) {
return false;
}
// Token expired?
return !(date.valueOf() > (new Date().valueOf() + (offsetSeconds * 1000)));
};
return JwtHelper;
}());
exports.JwtHelper = JwtHelper;
/**
* Checks for presence of token and that token hasn't expired.
* For use with the @CanActivate router decorator and NgIf
*/
function tokenNotExpired(tokenName, jwt) {
if (tokenName === void 0) { tokenName = AuthConfigConsts.DEFAULT_TOKEN_NAME; }
var token = jwt || localStorage.getItem(tokenName);
var jwtHelper = new JwtHelper();
return token != null && !jwtHelper.isTokenExpired(token);
}
exports.tokenNotExpired = tokenNotExpired;
exports.AUTH_PROVIDERS = [
{
provide: AuthHttp,
deps: [http_1.Http, http_1.RequestOptions],
useFactory: function (http, options) {
return new AuthHttp(new AuthConfig(), http, options);
}
}
];
function provideAuth(config) {
return [
{
provide: AuthHttp,
deps: [http_1.Http, http_1.RequestOptions],
useFactory: function (http, options) {
return new AuthHttp(new AuthConfig(config), http, options);
}
}
];
}
exports.provideAuth = provideAuth;
var hasOwnProperty = Object.prototype.hasOwnProperty;
var propIsEnumerable = Object.prototype.propertyIsEnumerable;
function toObject(val) {
if (val === null || val === undefined) {
throw new TypeError('Object.assign cannot be called with null or undefined');
}
return Object(val);
}
function objectAssign(target) {
var source = [];
for (var _i = 1; _i < arguments.length; _i++) {
source[_i - 1] = arguments[_i];
}
var from;
var to = toObject(target);
var symbols;
for (var s = 1; s < arguments.length; s++) {
from = Object(arguments[s]);
for (var key in from) {
if (hasOwnProperty.call(from, key)) {
to[key] = from[key];
}
}
if (Object.getOwnPropertySymbols) {
symbols = Object.getOwnPropertySymbols(from);
for (var i = 0; i < symbols.length; i++) {
if (propIsEnumerable.call(from, symbols[i])) {
to[symbols[i]] = from[symbols[i]];
}
}
}
}
return to;
}
/**
* Module for angular2-jwt
* @experimental
*/
var AuthModule = AuthModule_1 = (function () {
function AuthModule(parentModule) {
if (parentModule) {
throw new Error('AuthModule is already loaded. Import it in the AppModule only');
}
}
AuthModule.forRoot = function (config) {
return {
ngModule: AuthModule_1,
providers: [
{ provide: AuthConfig, useValue: config }
]
};
};
return AuthModule;
}());
AuthModule = AuthModule_1 = __decorate([
core_1.NgModule({
imports: [http_1.HttpModule],
providers: [AuthHttp, JwtHelper]
}),
__param(0, core_1.Optional()), __param(0, core_1.SkipSelf()),
__metadata("design:paramtypes", [AuthModule])
], AuthModule);
exports.AuthModule = AuthModule;
var AuthModule_1;
//# sourceMappingURL=angular2-jwt.js.map
;