Skip to content

Whitelist and revoke tokens

This optional feature gives you the option of revoking tokens on demand or after a certain idle timeout. A revoked token will fail verification.

This requires a database backend to store tokens. Support for Redis is built in, but you can also roll your own.

The whitelist works by storing the token ID (jti) every time you generate a token. The token is stored until its expiry time (exp) or idle timeout has elapsed (if your token have no expiry time and you don't use idle timeout they will be stored forever)

When you call Jotbox.verified_payload it always checks the whitelist. If the token is not in whitelist it raises a jotbox.RevokedTokenerror

Use the redis whitelist

The built in redis whitelist is simple to use. Import it like this:

from jotbox.whitelist.redis import RedisWhitelist

Instantiate from redis URL:

...
my_whitelist = RedisWhitelist('redis://localhost')

If you want more control over how the redis connection pool is created, you can pass in an redis.asyncio.Redis instance directly:

...
from redis.asyncio import Redis

my_redis = Redis(...)
my_whitelist = RedisWhitelist(my_redis)

You can also set a custom key prefix if you'd like (the default prefix is JB:WHITE:):

my_whitelist = RedisWhitelist(my_redis, key_prefix="WHITELISTED_TOKEN:")

Now pass your whitelist when creating the Jotbox instance:

jot = Jotbox[MyPayload](
    ...,
    whitelist=my_whitelist
)

To revoke a token (e.g. when a user logs out), pass the verified payload to revoke_payload:

payload = await jot.verified_payload(encoded_token)
await jot.revoke_payload(payload)

Idle timeout

The idle timeout setting tells jotbox to automatically delete tokens from the whitelist after a number of seconds of inactivity.

When used in conjunction with expires_at the token is removed from whitelist once either the idle timeout or expiry time elapses, whichever happens first.

This can be particularly useful for login sessions as it allows you to automatically log out the user after a period of inactivity while still allowing a long total expiry time on the session.

To use this you need to pass both idle_timeout argument to Jotbox along with whitelist:

jot = Jotbox[MyPayload](
    ...,
    expires_at=3600*24, # Expire after 24 hours when not idle
    idle_timeout=3600, # Revoke after 1 hour of inactivity
    whitelist=my_whitelist
)
token = await jot.create_token()
encoded_token = token.token

# User sends the token in API call
valid_payload = await jot.verified_payload(encoded_token)
# Success

await asyncio.sleep(3601) # No activity during idle timeout

await jot.verified_payload(encoded_token)
# raises RevokedTokenerror(...)

Use other storage backends

You don't have to use redis for your whitelist. You can create a subclass of the abstract class jotbox.whitelist.base.Whitelist and use any database/storage method you want.

You'll need to implement the add, exists, touch and delete methods.

Check source code of the redis whitelist for a reference implementation.

Note that with redis, expiry times are handled by redis itself. With other databases you may need to explicitly check and clean up expired tokens.