Replacing Session Tokens with OAuth Access Tokens

Summary

Using OAuth 2 to authenticate with Synapse has many benefits over using older authentication mechanisms. We can try to consolidate authentication services to using OAuth flows wherever possible. This document focuses on replacing session tokens with OAuth access/refresh tokens for first-party browser-based requests.

We primarily use the session token to authorize a user by storing it in the browser in a *.synapse.org HttpOnly cookie. On the client side, the same mechanism can be used with OAuth access tokens (and optionally, refresh tokens).

These access and refresh tokens can be bound to our bootstrapped, ‘first-party’ OAuth client with ID 0. Currently, Client 0 is only used to generate internal access tokens. Client 0 cannot be used to issue tokens with the authorization code flow, so users can only generate these external access tokens using their username and password, or authentication with an external identity provider.

Open question: should our default approach be extending the login services, or deprecating them for new ‘v2’ services? (If we want to eventually get rid of session tokens, it may be easier to ensure clients are using the a new login endpoint, rather than potentially modifying a response body.

To use OAuth tokens in place of session tokens, we must

  • Add functionality to return a client 0 bound access token (and optional refresh token) when

    • A user authenticates with username and password

    • A user authenticates with an external IdP (e.g. Google)

  • Allow client 0 to refresh tokens without a password (see also: Requirements for OAuth 2 public clients)

    • Permitting the creation of public clients is not necessary for this feature, but may influence the design/implementation because client 0 is a kind of public client because it has no credentials--but it’s also kind of not a public client because it is bootstrapped and first-party only.

  • Extend services that require a session token to accept an access token

    • POST /termsOfUse

Services

If we have the opportunity, we can also clean up the API a bit (decisions depend on whether these services are new

  • LoginResponse could extend Session (LoginResponse contains the same fields, and an authenticationReceipt)

Endpoint

Request Body

Response Body

Notes

Endpoint

Request Body

Response Body

Notes

POST /login

LoginRequest

LoginResponse

LoginRequest may support an additional boolean refreshToken field that defines whether a refresh token should be returned.

In addition to the existing fields, LoginResponse will include accessToken and (if specified) refreshToken. (If a v2 service, no sessionToken would be returned)

The tokens are bound to client 0, the “first-party” Synapse OAuth client.

POST /oauth2/session

OAuthValidationRequest

Session

This is the default login endpoint for users who sign in through external IdPs, like Google. Session can be extended to return an accessToken. (if a v2 service, no sessionToken would be returned)

POST /termsOfUse

Session

None

Extension/replacement of Session as stated above, requiring a valid accessToken (or sessionToken).

This request requires a Session because a user must agree to the terms of use before a token can be used to authenticate.

Other Considerations and Questions

  • Should access/refresh tokens issued to client 0 have different durations?

  • Should we implement the single-use refresh token revocation scheme outlined in Requirements for OAuth 2 public clients?

    • Refresh tokens are already single-use. The gist of the extension is that if an expired refresh token is used, the related active refresh token is also expired.