@fullerstack/ngx-jwt
Version:
A simple JWT library for Angular applications
186 lines (179 loc) • 6.69 kB
JavaScript
import { CommonModule } from '@angular/common';
import * as i0 from '@angular/core';
import { NgModule, Injectable } from '@angular/core';
import * as i1 from '@fullerstack/ngx-config';
import { DefaultApplicationConfig } from '@fullerstack/ngx-config';
import * as i2 from '@fullerstack/ngx-logger';
import { Base64 } from 'js-base64';
import { mergeWith, cloneDeep } from 'lodash-es';
/**
* @license
* Copyright Neekware Inc. All Rights Reserved.
*
* Use of this source code is governed by a proprietary notice
* that can be found at http://neekware.com/license/PRI.html
*/
class JwtModule {
}
JwtModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: JwtModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
JwtModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: JwtModule, imports: [CommonModule] });
JwtModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: JwtModule, imports: [[CommonModule]] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: JwtModule, decorators: [{
type: NgModule,
args: [{
imports: [CommonModule],
}]
}] });
/**
* @license
* Copyright Neekware Inc. All Rights Reserved.
*
* Use of this source code is governed by a proprietary notice
* that can be found at http://neekware.com/license/PRI.html
*/
/**
* Default configuration - JWT module
*/
const DefaultJwtConfig = {
// default of 1 second. frontend specific
networkDelay: 1,
// some backend may still honor requests by `x` seconds after expiry
expiryLeeway: 5,
};
/**
* @license
* Copyright Neekware Inc. All Rights Reserved.
*
* Use of this source code is governed by a proprietary notice
* that can be found at http://neekware.com/license/PRI.html
*/
/**
* An injectable class that handles JWT service
*/
class JwtService {
/**
* Class constructor
* @param options an optional configuration object
*/
constructor(config, logger) {
this.config = config;
this.logger = logger;
this.nameSpace = 'JWT';
this.options = DefaultApplicationConfig;
this.options = mergeWith(cloneDeep({ jwt: DefaultJwtConfig }), this.config.options, (dest, src) => (Array.isArray(dest) ? src : undefined));
this.logger.info(`[${this.nameSpace}] JwtService ready ...`);
}
/**
* Gets the payload portion of a JWT token
* @param token JWT token (base64 encrypted)
* @returns a payload object or null if decode fails
*/
getPayload(token) {
let parts = [];
try {
parts = token.split('.');
if (parts.length !== 3) {
throw Error('JWT must have 3 parts');
}
}
catch (e) {
this.logger.error(e.message);
return undefined;
}
try {
const decoded = Base64.decode(parts[1]);
const payload = JSON.parse(decoded);
return payload;
}
catch (e) {
this.logger.error('Cannot decode the token');
}
return undefined;
}
/**
* Tells if a JWT is token is expired
* @param payload JWT payload object
* @return true if JWT is already expired, else false
*/
isExpired(payload) {
if (typeof payload === 'string') {
payload = this.getPayload(payload);
}
if (payload) {
const offset = (parseInt(payload.lee, 10) || this.options.jwt.expiryLeeway) * 1000;
const now = this.utcSeconds();
const expiry = this.utcSeconds(payload.exp);
const expired = now > expiry + offset;
return expired;
}
return true;
}
/**
* Calculates the next refresh time
* @param payload JWT payload object
* @param offset if true, a random time is added to the refresh time
* where networkDelay < random < leeway
* @returns total number of seconds till expiry or 0 if token is expired
*/
getRefreshTime(payload, offset = true) {
if (typeof payload === 'string') {
payload = this.getPayload(payload);
}
if (payload && !this.isExpired(payload)) {
const now = this.utcSeconds();
const expiry = this.utcSeconds(payload.exp);
const refresh = Math.floor((expiry - now) / 1000);
const random = this.getRandomOffset(payload);
const time = offset ? refresh + random : refresh;
return time;
}
return 0;
}
/**
* Calculates a random number where networkDelay < random < leeway
* @param payload JWT payload object
* @returns a random total number of seconds
*/
getRandomOffset(payload) {
if (typeof payload === 'string') {
payload = this.getPayload(payload);
}
const leeway = payload?.leeway || payload?.lee || this.options?.jwt?.expiryLeeway;
const range = {
lower: 1,
upper: leeway - this.options?.jwt?.networkDelay || 2,
};
return Math.floor(Math.random() * range.upper + range.lower);
}
/**
* Calculates the UTC value of date/time in seconds
* @param input date/time in seconds
* @returns UTC value of date/time in seconds
*/
utcSeconds(input) {
return input ? new Date(0).setUTCSeconds(input).valueOf() : new Date().valueOf();
}
}
JwtService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: JwtService, deps: [{ token: i1.ConfigService }, { token: i2.LoggerService }], target: i0.ɵɵFactoryTarget.Injectable });
JwtService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: JwtService, providedIn: 'root' });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: JwtService, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}], ctorParameters: function () { return [{ type: i1.ConfigService }, { type: i2.LoggerService }]; } });
/**
* @license
* Copyright Neekware Inc. All Rights Reserved.
*
* Use of this source code is governed by a proprietary notice
* that can be found at http://neekware.com/license/PRI.html
*/
/**
* JWT config declaration
*/
class JwtConfig {
}
/**
* Generated bundle index. Do not edit.
*/
export { DefaultJwtConfig, JwtConfig, JwtModule, JwtService };
//# sourceMappingURL=fullerstack-ngx-jwt.mjs.map