auth-backend: clean up naming and types of TokenFactory time handling
This commit is contained in:
@@ -60,11 +60,11 @@ function jwtKid(jwt: string): string {
|
||||
|
||||
describe('TokenFactory', () => {
|
||||
it('should issue valid tokens signed by a listed key', async () => {
|
||||
const keyDuration = 5;
|
||||
const keyDurationSeconds = 5;
|
||||
const factory = new TokenFactory({
|
||||
issuer: 'my-issuer',
|
||||
keyStore: new MemoryKeyStore(),
|
||||
keyDuration,
|
||||
keyDurationSeconds,
|
||||
logger,
|
||||
});
|
||||
|
||||
@@ -87,7 +87,7 @@ describe('TokenFactory', () => {
|
||||
iat: expect.any(Number),
|
||||
exp: expect.any(Number),
|
||||
});
|
||||
expect(payload.exp).toBe(payload.iat + keyDuration * 1000);
|
||||
expect(payload.exp).toBe(payload.iat + keyDurationSeconds * 1000);
|
||||
});
|
||||
|
||||
it('should generate new signing keys when the current one expires', async () => {
|
||||
@@ -97,7 +97,7 @@ describe('TokenFactory', () => {
|
||||
const factory = new TokenFactory({
|
||||
issuer: 'my-issuer',
|
||||
keyStore: new MemoryKeyStore(),
|
||||
keyDuration: 5,
|
||||
keyDurationSeconds: 5,
|
||||
logger,
|
||||
});
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import moment from 'moment';
|
||||
import { TokenIssuer, TokenParams, KeyStore, AnyJWK } from './types';
|
||||
import { JSONWebKey, JWK, JWS } from 'jose';
|
||||
import { Logger } from 'winston';
|
||||
@@ -28,7 +29,7 @@ type Options = {
|
||||
/** Key store used for storing signing keys */
|
||||
keyStore: KeyStore;
|
||||
/** Expiration time of signing keys in seconds */
|
||||
keyDuration: number;
|
||||
keyDurationSeconds: number;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -49,16 +50,16 @@ export class TokenFactory implements TokenIssuer {
|
||||
private readonly issuer: string;
|
||||
private readonly logger: Logger;
|
||||
private readonly keyStore: KeyStore;
|
||||
private readonly keyDuration: number;
|
||||
private readonly keyDurationSeconds: number;
|
||||
|
||||
private keyExpiry?: number;
|
||||
private keyExpiry?: moment.Moment;
|
||||
private privateKeyPromise?: Promise<JSONWebKey>;
|
||||
|
||||
constructor(options: Options) {
|
||||
this.issuer = options.issuer;
|
||||
this.logger = options.logger;
|
||||
this.keyStore = options.keyStore;
|
||||
this.keyDuration = options.keyDuration;
|
||||
this.keyDurationSeconds = options.keyDurationSeconds;
|
||||
}
|
||||
|
||||
async issueToken(params: TokenParams): Promise<string> {
|
||||
@@ -68,7 +69,7 @@ export class TokenFactory implements TokenIssuer {
|
||||
const sub = params.claims.sub;
|
||||
const aud = 'backstage';
|
||||
const iat = Math.floor(Date.now() / MS_IN_S);
|
||||
const exp = iat + this.keyDuration * MS_IN_S;
|
||||
const exp = iat + this.keyDurationSeconds * MS_IN_S;
|
||||
|
||||
this.logger.info(`Issuing token for ${sub}`);
|
||||
|
||||
@@ -89,7 +90,7 @@ export class TokenFactory implements TokenIssuer {
|
||||
|
||||
for (const key of keys) {
|
||||
// Allow for a grace period of another full key duration before we remove the keys from the database
|
||||
const expireAt = key.createdAt.add(3 * this.keyDuration, 'seconds');
|
||||
const expireAt = key.createdAt.add(3 * this.keyDurationSeconds, 's');
|
||||
if (expireAt.isBefore()) {
|
||||
expiredKeys.push(key);
|
||||
} else {
|
||||
@@ -116,14 +117,14 @@ export class TokenFactory implements TokenIssuer {
|
||||
private async getKey(): Promise<JSONWebKey> {
|
||||
// Make sure that we only generate one key at a time
|
||||
if (this.privateKeyPromise) {
|
||||
if (this.keyExpiry && Date.now() < this.keyExpiry) {
|
||||
if (this.keyExpiry?.isAfter()) {
|
||||
return this.privateKeyPromise;
|
||||
}
|
||||
this.logger.info(`Signing key has expired, generating new key`);
|
||||
delete this.privateKeyPromise;
|
||||
}
|
||||
|
||||
this.keyExpiry = Date.now() + this.keyDuration * MS_IN_S;
|
||||
this.keyExpiry = moment().add(this.keyDurationSeconds, 'seconds');
|
||||
const promise = (async () => {
|
||||
// This generates a new signing key to be used to sign tokens until the next key rotation
|
||||
const key = await JWK.generate('EC', 'P-256', {
|
||||
|
||||
@@ -37,7 +37,7 @@ export async function createRouter(
|
||||
const logger = options.logger.child({ plugin: 'auth' });
|
||||
|
||||
const baseUrl = `${options.config.getString('backend.baseUrl')}/auth`;
|
||||
const keyDuration = 3600;
|
||||
const keyDurationSeconds = 3600;
|
||||
|
||||
const keyStore = await DatabaseKeyStore.create({
|
||||
database: options.database,
|
||||
@@ -45,7 +45,7 @@ export async function createRouter(
|
||||
const tokenIssuer = new TokenFactory({
|
||||
issuer: baseUrl,
|
||||
keyStore,
|
||||
keyDuration,
|
||||
keyDurationSeconds,
|
||||
logger: logger.child({ component: 'token-factory' }),
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user