Skip to content

Commit

Permalink
Support of RawPaseto-Otpions and 5sec default clockTolerance
Browse files Browse the repository at this point in the history
Optionally raw paseto-options (see
https://github.com/panva/paseto/tree/main/docs#v4verifytoken-key-options)
may be configured.

ignoreExpiry is removed from Attestation.DecodeParameters, as it can be
set via pasetoOptions.ignoreExp

This library supports a clockTolerance of 5sec per default, to account
for NTP inaccuracies between different servers
  • Loading branch information
tbergmueller committed May 16, 2024
1 parent ce5a2d5 commit 17bae69
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 8 deletions.
22 changes: 15 additions & 7 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { V4, errors } from 'paseto';
import { ConsumeOptions, V4, errors } from 'paseto';
import NodeCache from 'node-cache';

/**
Expand Down Expand Up @@ -35,10 +35,6 @@ type AttestationPayload = {
* Parameters to configure decoding options
*/
interface DecodeParameters {
/**
* If true, ignores expiry date, i.e. allows to decode already expired tokens
*/
ignoreExpiry?: boolean;
/**
* If true, token is decoded but not redeemed.
* This does not undo previous redemptions, so if a token is already redeemed, it will no longer be decode-able
Expand Down Expand Up @@ -122,6 +118,9 @@ class AttestationManager {
private keyServerUrl: string = "https://sip-keys.authenticvision.com/v4";
// stores token.jti together with the redeem date
private redeemedCache: NodeCache = new NodeCache();
private decodeOptions = {
clockTolerance: "5s"
};

constructor() {

Expand Down Expand Up @@ -184,7 +183,7 @@ class AttestationManager {
* @param params Optional Parameters, see docs
* @returns Attestation, when successfully decoded. Throws otherwise
*/
public async decode(token: string, params?: DecodeParameters): Promise<Attestation> {
public async decode(token: string, params?: DecodeParameters, pasetoOptions?: ConsumeOptions<true> ): Promise<Attestation> {
try {
const parsedToken = JSON.parse(Buffer.from(token.split('.')[3], 'base64').toString('utf-8'));

Expand All @@ -196,7 +195,16 @@ class AttestationManager {
// For demo-purposes, decode it even if expired
//const rawPayload = (await V4.verify(token, pubKey!, { ignoreExp: true, complete: true }))?.payload as AttestationTokenPayload;

const validatedPayload = await V4.verify(token, pubKey!, { ignoreExp: params?.ignoreExpiry, complete: true });
// Use default settings
const defaultOptions: ConsumeOptions<true> = {
complete: true,
clockTolerance: this.decodeOptions.clockTolerance
};

// Any provided pasetoOptions will overwrite the default options:
const mergedOptions: ConsumeOptions<true> = Object.assign({}, defaultOptions, pasetoOptions);

const validatedPayload = await V4.verify(token, pubKey!, mergedOptions);
const attestation = new Attestation(validatedPayload?.payload as AttestationPayload, token);

// Throws if key already redeemed
Expand Down
27 changes: 26 additions & 1 deletion tests/decoding.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,32 @@ describe('Decoding tests', () => {
});

it('Decodes expired token, when expiry is ignored', async () => {
const attestation = await attestationDecoder.decode(testTokenExpired, {ignoreExpiry:true});
const pasetoOptions = {ignoreExp:true}
const attestation = await attestationDecoder.decode(testTokenExpired, {}, pasetoOptions);
expect(attestation?.getSlid()).toEqual("Z45JBJR6S9");
});

it('Decodes token less than 5sec in future (default)', async () => {
// paseto-options allow to specify now
// Decode token is issued 2023-04-20T16:54:01Z
const pasetoOptions = {now: new Date("2023-04-20T16:54:01Z")}
const attestation = await attestationDecoder.decode(testToken, {}, pasetoOptions);
expect(attestation?.getSlid()).toEqual("Z45JBJR6S9");
});

it('Does not decode token more than 5sec in future (default)', async () => {
// paseto-options allow to specify now
// Decode token is issued 2023-04-20T16:54:01Z
const pasetoOptions = {now: new Date("2023-04-20T16:53:55Z")} // this is 6 seconds before issuing date
await expect(attestationDecoder.decode(testToken, {}, pasetoOptions)).rejects.toThrow(AttestationError);
});

it('Does decode token more than 5sec in future (configured)', async () => {
// paseto-options allow to specify now
// Decode token is issued 2023-04-20T16:54:01Z
// this is 6 seconds before issuing date, however, we also define 10s tolerance
const pasetoOptions = {now: new Date("2023-04-20T16:53:55Z"), clockTolerance: "10s"}
const attestation = await attestationDecoder.decode(testToken, {}, pasetoOptions);
expect(attestation?.getSlid()).toEqual("Z45JBJR6S9");
});
});
Expand Down

0 comments on commit 17bae69

Please sign in to comment.