# Revoking Tokens

```{note}
This functionality is introduced in version 0.3.0.
```

Sometimes, you want to revoke a token. As João Angelo wrote:

> In general the easiest answer would be to say that you
> cannot revoke a JWT token, but that's simply not true. The
> honest answer is that the cost of supporting JWT
> revocation is sufficiently big for not being worth most of
> the times....

There are plenty of times that you want to revoke a token.
However, you can't just reach into the person's browser and
remove it, though. You have to indicate to the browser (or
whatever client) that the token is no longer good.

If [expiration](./expiry.md) is not good enough, and you
need "immediate token revocation" as it's called, then the
`Authenticator` has the functionality for you.

Each token generated by an `Authenticator` has the
[`"jti"`](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.7)
claim in it. This allows you to "track" the issued JWT and,
if needed, invalidate it.

To invalidate a token, you'll need to store the identifier
somewhere so that you can tell if it's good or not. This is
essentially a _session-tracking_ mechanism.

Here's an example of the two-step process for how to do this
with the `jwtdown-fastapi`.

## Override `jti` methods

There are there are three methods to override:

* `get_session_getter` which uses FastAPI's dependency
  injection mechanism to get an instance of the thing you
  use to manage session data
* `jti_created` which alerts you to when a new JWT is
  created and there is a new `"jti"` claim which will happen
  during the login process
* `jti_destroyed` which alerts you to when a JWT has expired
  and the `"jti"` claim is no longer any good, or during the
  logout process
* `validate_jti` will get called whenever someone tries to
  access a protected endpoint and, if it returns `False`,
  then the person will not be allowed to access that
  protected endpoint

```python
# authenticator.py
import os
from fastapi import Depends
from jwtdown_fastapi.authentication import Authenticator
from queries.accounts import AccountRepo, AccountOut, Account
from queries.sessions import SessionRepo


class MyAuthenticator(Authenticator):
    # Other overridden methods

    def get_session_getter(self, session_repo: SessionRepo = Depends()):
        return session_repo

    async def jti_created(self, jti, account, session_repo):
        await session_repo.create(jti, account)

    async def jti_destroyed(self, jti, session_repo):
        await session_repo.delete(jti)

    async def validate_jti(self, jti, session_repo):
        return session_repo.get(jti) is not None


authenticator = MyAuthenticator(os.environ["SIGNING_KEY"])
```

## Implement a revocation endpoint

In your application, you will need a way to revoke a valid
JWT. You can create an endpoint that lets you do that.

```python
# router.py

@router.delete("/api/sessions/{account_id}", response_model=bool)
async def delete_session(
    account_id: str,
    account_data: dict = Depends(authenticator.get_current_account_data),
    session_repo: SessionRepo = Depends(),
) -> bool:
    if "admin" in account_data["roles"]:
        session_repo.delete_sessions(account_id)
        return True
    return False
```
