jwti
TypeScript icon, indicating that this package has built-in type declarations

1.0.2 • Public • Published

jwti

JWT Invalidation uses jsonwebtoken and redis to provide a way to handle multi token/user/client jwt invalidation.

Setup

import jwt from 'jsonwebtoken';
import { createClient } from 'redis';
import { Jwti } from 'jwti';

(async () => {
  const redis = createClient();
  await redis.connect();

  const jwti = new Jwti(jwt, redis);
  //...
})();

Invalidate an specific token

const token = await jwti.sign('payload', 'secret');

await jwti.invalidate(token);

// Throws an InvalidatedTokenError
await jwti.verify(token);

Invalidate all previously signed tokens for a user

const token = await jwti.sign('payload', 'secret', { user: 1 });

await jwti.invalidate({ user: 1 });

// Throws an InvalidatedTokenError
await jwti.verify(token);

Invalidate all previously signed tokens for a client

const token = await jwti.sign('payload', 'secret', { client: 'mobile' });

await jwti.invalidate({ client: 'mobile' });

// Throws an InvalidatedTokenError
await jwti.verify(token);

Invalidate all previously signed tokens for a user on a client

const token = await jwti.sign('payload', 'secret', {
  user: 1,
  client: 'mobile',
});

await jwti.invalidate({ user: 1, client: 'mobile' });

// Throws an InvalidatedTokenError
await jwti.verify(token);

Revert invalidations

tokens

const token = await jwti.sign('payload', 'secret');

await jwti.invalidate(token);

const reverted = await jwti.revert(token);

// Outputs 'payload'
await jwti.verify(token);

users

const token = await jwti.sign('payload', 'secret', { user: 1 });

await jwti.invalidate({ user: 1 });

const reverted = await jwti.revert({ user: 1 });

// Outputs 'payload'
console.log(await jwti.verify(token));

clients

const token = await jwti.sign('payload', 'secret', { client: 'mobile' });

await jwti.invalidate({ client: 'mobile' });

const reverted = await jwti.revert({ client: 'mobile' });

// Outputs 'payload'
console.log(await jwti.verify(token));

user-client comabinations

const token = await jwti.sign('payload', 'secret', {
  user: 1,
  client: 'mobile',
});

await jwti.invalidate({ user: 1, client: 'mobile' });

const reverted = await jwti.revert({ user: 1, client: 'mobile' });

// Outputs 'payload'
await jwti.verify(token);

Quick reminder:

all new tokens (signed after an invalidation) will be valid

const firstToken = await jwti.sign('payload', 'secret', { user: 1 });

await jwti.invalidate({ user: 1 });

const secondToken = await jwti.sign('payload', 'secret', { user: 1 });

// Throws an InvalidatedTokenError
console.log(await jwti.verify(firstToken));

// Outputs 'payload'
console.log(await jwti.verify(secondToken));

Important:

Whenever possible, use precise flag (check full documentation for details)

Short explanation: jwti uses jsonwebtoken under the hood and jsonwebtoken generated iats (issuedAt property) aren't precise, it strips out the milleseconds.

E.g: 1648507842001 becomes 1648507842 hence 1648507842000; 1648507842999 also becomes 1648507842 hence 1648507842000

jwti invalidations are precise, and take milleseconds into account. If an invalidation was set on the SAME SECOND of a token issuation, that token would be valid altought it was signed before the invalidation.

E.g:

token.iat = 1648507842001 becomes 1648507842 hence 1648507842000; invalidation.timesstamp = 1648507842123;

token.iat < invalidation.timestamp => token is valid.

This would cause the following weird scenario:

NOT using precise flag:

const user = { name: 'John Doe', id: 1 };

const firstToken = await jwti.sign(user, 'secret', { user: 1 });

await jwti.invalidate({ user: 1 });

const secondToken = await jwti.sign(user, 'secret', { user: 1 });

// Outputs 'payload'
console.log(await jwti.verify(firstToken));

// Outputs 'payload'
console.log(await jwti.verify(secondToken));

//Both tokens are valid even though one of them was issued before an invalidation was made.

So jwti can generate it's own iat with milleseconds precision to get around that problem. You just need pass precise: true in the options object.

USING precise flag:

const user = { name: 'John Doe', id: 1 };

const firstToken = await jwti.sign(user, 'secret', { user: 1, precise: true });

await jwti.invalidate({ user: 1 });

const secondToken = await jwti.sign(user, 'secret', { user: 1, precise: true });

// Throws an InvalidatedTokenError without a chance of failing
console.log(await jwti.verify(firstToken));

// Outputs 'payload'
console.log(await jwti.verify(secondToken));

Package Sidebar

Install

npm i jwti

Weekly Downloads

8

Version

1.0.2

License

MIT

Unpacked Size

49.4 kB

Total Files

13

Last publish

Collaborators

  • marcosilva