The following document outlines the specifications for the sessions management of the Standard Notes syncing server system.
The proposed sessions management system will be part of the 004 release, which includes the new API version 20200115 on the server side.
Any account version can use this new API version. That includes 001, 002, 003 and the upcoming 004 version. Because the newest client will support these accounts, and the API version will still be hardcoded to 20200115. But only those who upgrade their account version to 004 will be able to use this new session management feature.
The following message will be shown to them once the account upgrade succeeds:
Your session with the server has been upgraded to the latest version. You will need to re-enter your account password on your other devices to continue syncing.
The SNJS library will be updated to use the new API version.
| Field | Type | Description |
|---|---|---|
| uuid | string | Unique identifier of the session |
| user_uuid | string | Unique identifier of the user |
| user_agent | string | The user agent used to create the session |
| api_version | string | The server API version used to create the session |
| access_token | string | The access token used to authenticate requests |
| refresh_token | string | The refresh token used to extend tokens |
| access_expiration | datetime | The expiration time of the access token |
| renew_expiration | datetime | The expiration time of the refresh token |
| created_at | datetime | Date and time of creation of the session |
| updated_at | datetime | Last updated date and time of the session |
- Each
sessionincludes the API version they were created with. This way we can deny sessions for a given API version if we detect a vulnerability with that version in the future access_tokenandrefresh_tokentokens are both generated usingActiveRecord::SecureToken- Sessions are created in the following cases:
- When a user signs in
- When a user registers a new account
- 20200115
The Authorization request header field is used by clients to make authenticated request. Bearer is the only authentication scheme allowed.
The client must send the access token generated by the session, in the Authorization header. For example:
GET /sessions HTTP/1.1
Host: sync.standardnotes.org
Authorization: Bearer <access token>
Below is a list of endpoints that will be available to manage sessions:
| Method | URL | Params | Description | Successful response code |
|---|---|---|---|---|
POST |
/auth/sign_out | None | Terminates the current session | 204 |
DELETE |
/session | uuid | Terminates the specified session by UUID | 204 |
DELETE |
/sessions | None | Terminates all sessions, except the current one | 204 |
GET |
/sessions | None | Lists all sessions active sessions | 200 |
POST |
/session/token/refresh | refresh_token | Obtains new pair of access_token and refresh_token |
200 |
A successful request to GET /sessions returns the following JSON response:
{
"sessions": [
{
"uuid": "xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx",
"user_agent": "<product> / <product-version> <comment>",
"api_version": "xxxxyyzz",
"current": "<boolean>",
"created_at": "2020-01-01T00:00:00.000Z"
}
...
]
}Tokens can be obtained every time the user performs the following actions:
- When a user signs in
- When a user registers an account
- When the tokens are refreshed
When an expired access_token is provided in the Authorization HTTP header, the following JSON response is returned:
HTTP Status Code: 498 Expired Access Token
{
"error": {
"tag": "expired-access-token",
"message": "The provided access token has expired."
}
}To continue accessing resources, the access_token must be refreshed. That is, the current access_token is replaced with a new one with an extended expiration date.
To refresh an access_token, a valid refresh_token is needed. This refresh_token must meet the following requirements:
- It should belong to the session of the
access_token - It should not be expired
Since the refresh_token is of single-use, a new refresh_token is obtained when the access_token is refreshed.
Refreshing tokens is a process that is transparent to the user, meaning that the client will perform the requests to keep valid tokens without user intervention.
Here's how to refresh tokens:
-
Send a
POSTrequest to/session/token/refresh. The body should contain a JSON paylaod with therefresh_token:POST /session/token/refresh HTTP/1.1 Host: sync.standardnotes.org Authorization: Bearer <access token> { "refresh_token": "R_xxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx" } -
The
refresh_tokenis validated on the server. Depending of the circumstances, there should be two outcomes:-
The provided
refresh_tokenis valid. If so, a new pair of tokens is generated and the following JSON response is returned:{ "token": "xxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx", "session": { "refresh_expiration": 1583020800, "refresh_token": "xxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx", } } -
The provided
refresh_tokenis expired. If so, the following JSON response is returned:HTTP Status Code:
400 Bad Request{ "error": { "tag": "expired-refresh-token", "message": "The refresh token has expired." } }User must start a new session by re-entering their credentials.
-
Sessions should be terminated after a period of inactivity. This is for best security practices.
Long-lived sessions are a good choice for our use case, because it can build a better user experience than expiring sessions for a short idle-timeout.
- A
sessionthat remains inactive for1 yearwill be terminated, along with alltokens
| Name | Type | Expiration |
|---|---|---|
access |
Short-lived | 60 days |
refresh |
Long-lived | 1 year |
- A
refreshtoken is of single-use, while anaccesstoken can be used as long as it is not expired
The following is a list of several threats and their corresponding mitigations for the proposed sessions system:
A token may be disclosed to unauthorized users
Mitigation(s):
- Clients must store tokens safely
- Clients must use HTTPS when making request with the tokens
An attacker may steal a token from the user's device and/or browser
Mitigation(s):
- Tokens may be stolen in some way. Users have the ability to revoke any stolen tokens if necessary
-
Web: by default,
localStorageis used on thewebapplication. -
Desktop: SNJS storage will be used. It leverages the system keychain through Electron.
-
Mobile: On this platform, the react-native-keychain library is used.
-
The sole purpose of the
refresh_tokenis to extend a user session. This is done by generating new tokens, and invalidating the current ones.Also, it limits the use of user credentials by not requiring them to obtain a new
access_token. This brings greater user experience than having to re-enter credentials every time theaccess_tokenis expired. -
This is a major security risk. An attacker could potentially gain access to the
access_tokenand abuse the user's account until the token is expired.
- JWT: A JSON Web Token is a compact, URL-safe means of representing claims to be transferred between two parties.
- Access token: Used to access protected resources.
- Refresh token: Used to obtain new access tokens.
- API version: The version of the API in use.
- Account version: The version of the SF specification used when creating this user's account. This value is updated when a user changes their password or updates their security version.