# OAuth2 Refresh Tokens

Due to how Kanidm authentication sessions were originally implemented they had short session times (1 hour) due to the
lack of privilege separation in tokens. Now with privilege separation being implemented session lengths have been
extended to 8 hours with possible increases in the future.

However, this leaves us with an issue with OAuth2 - OAuth2 access tokens are considered valid until their expiry and we
should not issue tokens with a validity of 8 hours or longer since that would allow rogue users to have a long window of
usage of the token before they were forced to re-auth. It also means that in the case that an account must be forcefully
terminated then the user would retain access to applications for up to 8 hours or more.

To prevent this, we need OAuth2 tokens to "check in" periodically to re-affirm their session validity.

This is performed with access tokens and refresh tokens. The access token has a short lifespan (proposed 15 minutes) and
must be refreshed with Kanidm which can check the true session validity and if the session has been revoked. This
creates a short window for revocation to propagate to OAuth2 applications since each OAuth2 application must
periodically check in to keep their access token alive.

## Risks

Refresh tokens are presented to the relying server where they receive an access token and an optional new refresh token.
Because of this, it could be possible to present a refresh token multiple times to proliferate extra refresh and access
tokens away from the system. Preventing this is important to limit where the tokens are used and monitor and revoke them
effectively.

In addition, old refresh tokens should not be able to be used once exchanged, they should be "at most once". If this is
not enforced then old refresh tokens can be used to gain access to sessions even if the associated access token was
expired by many hours and its refresh token was already used.

This is supported by
[draft oauth security topics section 2.2.2](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics#section-2.2.2)
and
[draft oauth security topics refresh token protection](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics#refresh_token_protection)

Refresh tokens must only be used by the client application associated. Kanidm strictly enforces this already with our
client authorisation checks. This is discussed in
[RFC6749 section 10.4](https://www.rfc-editor.org/rfc/rfc6749#section-10.4).

## Design

          ┌─────────────────────────────────────────┐
          │Kanidm                                   │
          │                                         │
          │ ┌─────────┐                ┌─────────┐  │
          │ │         │                │         │  │
          │ │         │                │         │  │
          │ │ Session │  3. Update     │ Session │  │
          │ │  NIB 1  │─────NIB───────▶│  NIB 2  │  │
          │ │         │                │         │  │
          │ │         │                │         │  │
          │ │         │                │         │  │
          │ └─────────┘                └─────────┘  │
          │   │                           │         │
          └───┼───────────────────────────┼─────────┘
         ┌────┘             ▲        ┌────┘          
         │                  │        │               
         │                  │        │               
    1. Issued               │   4. Issued            
         │                  │        │               
         │                  │        │               
         │                  │        │               
         ▼                  │        ▼               
     ┌───────┐              │    ┌───────┐           
     │       │              │    │       │           
     │Access │              │    │Access │           
     │   +   │              │    │   +   │           
     │Refresh│──2. Refresh──┘    │Refresh│           
     │ IAT 1 │                   │ IAT 2 │           
     │       │                   │       │           
     └───────┘                   └───────┘

In this design we associate a "not issued before" (NIB) timestamp to our sessions. For a refresh token to be valid for
issuance, the refresh tokens IAT must be greater than or equal to the NIB.

In this example were the refresh token with IAT 1 reused after the second token was issued, then this condition would
fail as the NIB has advanced to 2. Since IAT 1 is not greater or equal to NIB 2 then the refresh token _must_ have
previously been used for access token exchange.

In a replicated environment this system is also stable and correct even if a session update is missed.

                                              2.                                                       
                  ┌───────────────────────Replicate────────────────┐                                   
                  │                                                │                                   
                  │                                                │                                   
          ┌───────┼─────────────────────────────────┐       ┌──────┼──────────────────────────────────┐
          │Kanidm │                                 │       │Kanidm│                                  │
          │       │                                 │       │      ▼                                  │
          │ ┌─────────┐                ┌─────────┐  │       │ ┌─────────┐                 ┌─────────┐ │
          │ │         │                │         │  │       │ │         │                 │         │ │
          │ │         │                │         │  │       │ │         │                 │         │ │
          │ │ Session │  4. Update     │ Session │  │       │ │ Session │   7. Update     │ Session │ │
          │ │  NIB 1  │─────NIB───────▶│  NIB 2  │  │       │ │  NIB 1  │ ─────NIB───────▶│  NIB 3  │ │
          │ │         │                │         │  │       │ │         │                 │         │ │
          │ │         │                │         │  │       │ │         │                 │         │ │
          │ │         │                │         │  │       │ │         │                 │         │ │
          │ └─────────┘                └─────────┘  │       │ └─────────┘                 └─────────┘ │
          │   │                           │         │       │      ▲                        │         │
          └───┼───────────────────────────┼─────────┘       └──────┼────────────────────────┼─────────┘
         ┌────┘             ▲        ┌────┘                        │                   ┌────┘          
         │                  │        │                             │                   │               
         │                  │        │                             │                   │               
    1. Issued               │   5. Issued                          │              8. Issued            
         │                  │        │                             │                   │               
         │                  │        │                             │                   │               
         │                  │        │                             │                   │               
         ▼                  │        ▼                             │                   ▼               
     ┌───────┐              │    ┌───────┐                         │               ┌───────┐           
     │       │              │    │       │                         │               │       │           
     │Access │              │    │Access │                         │               │Access │           
     │   +   │              │    │   +   │                         │               │   +   │           
     │Refresh│──3. Refresh──┘    │Refresh│                         │               │Refresh│           
     │ IAT 1 │                   │ IAT 2 │─────6. Refresh──────────┘               │ IAT 3 │           
     │       │                   │       │                                         │       │           
     └───────┘                   └───────┘                                         └───────┘

In this example, we can see that the replication of the session with NIB 1 happens to the second Kanidm server, but the
replication of session with NIB 2 has not occurred yet. If the token that was later issued with IAT 2 was presented to
the second server it would still be valid and able to refresh since IAT 2 is greater or equal to NIB 1. This would also
prompt the session to advance to NIB 3 such that when replication begun again, the session with NIB 3 would take
precedence over the former NIB 2 session.

While this allows a short window where a former access token could be used on the second replica, this infrastructure
being behind load balancers and outside of an attackers influence significantly hinders the ability to attack this for
very little gain.

## Attack Detection

[draft oauth security topics section 4.14.2](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics#section-4.14.2)
specifically calls out that when refresh token reuse is detected then all tokens of the session should be canceled to
cause a new authorisation code flow to be initiated.

## Inactive Refresh Tokens

Similar
[draft oauth security topics section 4.14.2](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics#section-4.14.2)
also discusses that inactive tokens should be invalidated after a period of time. From the view of the refresh token
this is performed by an internal exp field in the encrypted refresh token.

From the servers side we will require a "not after" parameter that is updated on token activity. This will also require
inactive session cleanup in the server which can be extended into the session consistency plugin that already exists.

Since the act of refreshing a token is implied activity then we do not require other signaling mechanisms.

## Questions

Currently with authorisation code grants and sessions we issue these where the sessions are recorded in an async manner.
For consistency I believe the same should be true here but is there a concern with the refresh being issued but a slight
delay before it's recorded? I think given the nature of our future replication we already have to consider the
async/eventual nature of things, so this doesn't impact that further, and may just cause client latency in the update
process.

However, we also don't want a situation where our async/delayed action queues become too full or overworked. Maybe queue
monitoring/backlog issues are a separate problem though.
