-
-
Notifications
You must be signed in to change notification settings - Fork 203
Session Auth Flow
This document is a working draft. Please leave any and all comments in the discussion issue: https://github.com/directus/api/issues/1263
- Date: 6 September 2019
- Status: Proposed Recommendation (Draft)
- Author: @rijkvanzanten
- Implementation Status: Not Implemented
- Issue for Discussion: https://github.com/directus/api/issues/1263
- Introduction
- The Problem
- Short expiration time + no background refresh
- Multiple APIs
- Insecure storage
- Proposed Solution
- Detailed Design
- Start session
- Stop session
- Kill all sessions for user
- Detailed Design
- Drawbacks / considerations
- Alternatives
- Adoption Strategy
- Unresolved Questions
- Useful Links
- TL;DR
Authenticating into the API is one of the most foundational and crucial functionalities of the Directus API. Currently, the Directus API utilizes a system based on a JSON Web-Token (JWT) in order to provide the user with the ability to authenticate against the API without having to resubmit the user email and password in every request. While this system works relatively well for the secure server to server communication, there are a couple of things that are left to be desired when you're working with a Web App.
The most notable problem with relying on JWTs is storing it. The JWT is a key that gives the user full access to everything in the system that the user that's authenticated with. Therefore, you can consider the JWT to be as sensitive to information as a username and password combination.
When working with the JWT, the browser needs to store this information somewhere in order to be able to send it in the request to authenticate against the API. Right now, the Application (by relying on the JS SDK) stores this information in sessionStorage
.
While this works relatively well when using a single API endpoint, it has a couple of drawbacks that are hard to overcome:
The JS SDK can only refresh the token when the browser window is active and in the foreground. Therefore, if the user is not actively using the Application, they'll be logged as soon as the token expires. The expiration time of the Access Token is very short (by design).
As mentioned before, the JWT is the key to the house. We want to be able to be logged in to multiple APIs at the same time (multi-tenant) from the same application (or project) instance, which would mean that we'd have to store the key right next to the location of the API. This makes it way too easy for
There is no way to store information to the browser from JavaScript that is secure enough to hold these tokens. Every JavaScript that runs in the same context as the Application—whether that be third party analytics software, custom scripts, and extensions, or malicious packages that snuck into the core codebase—can read and write to the storage. When storing these high-sensitive keys combined with the APIs that they unlock, this is too big of a security vulnerability.
Add a third—next to JWTs and the Static Token—way of being authenticated in the API: Session Cookies.
Instead of returning a token or key, this login method will set a cookie to the browser that made the request. This cookie can then be used on the server-side to look up what user authenticated through this method. This form of authentication is very common and traditionally used in "regular" websites where some data needs to persist across the page.
We should add some new endpoints and update the current one to the API that the project can use to manage authentication:
Endpoint: POST /auth/authenticate
Param :
mode
: cookie / jwt
-
mode=cookie
On successful login, this endpoint will create a session cookie and return a 200 OK status indicating to the project that the user is successfully authenticated and that the cookie has been set.
-
mode=jwt
(If will work as the current flow)On successful login, this endpoint will return the
jwt
auth token and return a 200 OK status indicating to the project that the user is successfully authenticated.
Note: By default, the `mode` will be consider as `jwt`.
This should be the same as earlier
{
"email": "[email protected]",
"password": "d1r3ctu5"
}
This endpoint won't return any data on a successful login. On errors, it should match the output of the existing /auth/authenticate
endpoint.
Seeing that session cookie will not expire, we need to have a way to log out as well.
Endpoint: POST /auth/logout
This endpoint doesn't get any input. It will destroy the session data based on the cookie that's sent along in this request.
There's no JSON output either. The API will destroy the cookie and the session and return a 200 OK afterward.
Seeing that you can theoretically be logged in on multiple devices for an infinite amount of time, we need a way to log the user out of all devices they're logged into. This can be done with a "kill all sessions" endpoint.
Endpoint: /auth/logout/:user
Params:
user
: The ID of the Directus User
n/a
Either a empty 200 OK payload or an error object
This endpoint will logout the user from a particular session
Endpoint: /auth/logout/:user/:id
Params:
user
: The ID of the Directus User
id
: The ID of the user session
n/a
Either an empty 200 OK payload or an error object
This endpoint will return all the session of currently logged in user.
Endpoint: /auth/sessions
n/a
User sessions object or an empty payload with 200 status code.
Having an API with large throughput and a lot of users might introduce issues on a bigger scale.
I was researching a setup where we use refresh tokens next to the access token to be able to refresh an access token for a longer period of time. This would solve the staying logged in problem, but wouldn't do anything to negate the storing of tokens in the public client-side.
These should be new endpoints and not affect the current setup. I don't think it's a breaking change.
- What kind of errors can we run into when creating/destroying sessions and cookies? These need error objects and codes.
- Do we need a "kill all sessions" globally endpoint?
- Are there any foreseeable problems in CORS + cross-domain cookies between the API and projects that are on separate domains?
- https://logrocket.com/blog/jwt-authentication-best-practices/
- https://developer.okta.com/blog/2018/06/20/what-happens-if-your-jwt-is-stolen
- Add session cookie auth system
- Add three endpoints:
/auth/authenticate
,/auth/logout
,/auth/logout/:user
,/auth/logout/:user/:id
and/auth/sessions
Directus Internal Docs
Please see https://docs.directus.io for the usage guide.