Files
standardnotes-app-web/packages/docs/docs/specification/auth.md
2022-07-04 15:42:47 -05:00

13 KiB

id, title, sidebar_label, description, keywords, image, hide_title, hide_table_of_contents
id title sidebar_label description keywords image hide_title hide_table_of_contents
auth Auth API Auth Authentication portion of the Standard Notes API.
standard notes
docs
notes app
end-to-end encryption
sync
/img/logo.png false false

POST /auth

Registers a new user

api string The API version to use. Must not be null, otherwise oldest API version used. Latest value is "20200115"
created string Integer timestamp representing the date the client generated the account's encryption keys. Example "1622494310383"
email string The account email.
ephemeral boolean Whether the initial session created for this account is ephemeral ("Stay signed in" unchecked).
identifier string Should equal the account email.
origination string Should equal "registration"
password string The server password generated by the client from the user's master password.
pw_nonce string The nonce generated by the client for the user's encryption key.
version string The protocol version the client used to generate the user's encryption key. Latest is "004".

Response

{
	"session": {
		"access_token": "1:457b1f4b-88c2-4328-bf32-fe7dd9431d62:WwKgTEDUoEhxECu6",
		"refresh_token": "1:457b1f4b-88c2-4328-bf32-fe7dd9431d62:G-qEoZsFtoj~RLL-",
		"access_expiration": 1627678312000,
		"refresh_expiration": 1654051238000
	},
	"key_params": {
		"created": "1622494310383",
		"identifier": "foo@example.com",
		"origination": "registration",
		"pw_nonce": "d97ed41c581fe8c3e0dce7d2ee72afcb63f9f461ae875bae66e30ecf3d952900",
		"version": "004"
	},
	"user": {
		"uuid": "682f9deb-b75f-4d97-91fa-6fd82a482db1",
		"email": "foo@example.com"
	}
}

POST /auth/sign_in

Authenticates a user and returns a session.

api string The API version to use. Must not be null, otherwise oldest API version used. Latest value is "20200115"
email string The account email.
ephemeral boolean Whether the session created for this account is ephemeral ("Stay signed in" unchecked).
password string The server password generated by the client from the user's master password.

Response

{
	"session": {
		"access_token": "1:ee03808d-dd05-417c-9c87-d471e49bcc49:Q~-UoIpDhdtkii_t",
		"refresh_token": "1:ee03808d-dd05-417c-9c87-d471e49bcc49:Jn8UWzeHx2H5nZI5",
		"access_expiration": 1627678779000,
		"refresh_expiration": 1654051705000
	},
	"key_params": {
		"created": "1622494310383",
		"identifier": "foo@example.com",
		"origination": "registration",
		"pw_nonce": "d97ed41c581fe8c3e0dce7d2ee72afcb63f9f461ae875bae66e30ecf3d952900",
		"version": "004"
	},
	"user": {
		"uuid": "682f9deb-b75f-4d97-91fa-6fd82a482db1",
		"email": "foo@example.com"
	}
}

GET /auth/params

Queries the parameters used for key generation for an email address. Queried before signing into an account.

api string The API version to use. Must not be null, otherwise oldest API version used. Latest value is "20200115"
email string The account email.

Response

{
	"identifier": "foo@example.com",
	"pw_nonce": "d97ed41c581fe8c3e0dce7d2ee72afcb63f9f461ae875bae66e30ecf3d952900",
	"version": "004"
}

POST /auth/change_pw

Changes a user's password.

api string The API version to use. Must not be null, otherwise oldest API version used. Latest value is "20200115"
created string Integer timestamp representing the date the client generated the account's new encryption keys. Example "1622494310383"
identifier string The account email.
origination string Should equal "password-change"
current_password string The old server password generated by the client from the user's master password.
new_password string The new server password generated by the client from the user's master password.
pw_nonce string The nonce generated by the client for the user's encryption key.
version string The protocol version the client used to generate the user's encryption key. Latest is "004".

Response

{
	"session": {
		"access_token": "1:27d4fd8f-b730-4e0a-afd3-1600fb466aaa:HMgmZwV5k5ePt0vj",
		"refresh_token": "1:27d4fd8f-b730-4e0a-afd3-1600fb466aaa:wHuTeOB-qWGP3AE3",
		"access_expiration": 1627679129000,
		"refresh_expiration": 1654052055000
	},
	"key_params": {
		"created": "1622494310383",
		"identifier": "foo@example.com",
		"origination": "password-change",
		"pw_nonce": "be1974ff6fb1c541aa8c71fd3c66851b6492cf224b661c72daf44e0bef3096bb",
		"version": "004"
	},
	"user": {
		"uuid": "682f9deb-b75f-4d97-91fa-6fd82a482db1",
		"email": "foo@example.com"
	}
}

Sessions

Session Model

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
refresh_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 session includes 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
  • Sessions are created in the following cases:
    • When a user signs in
    • When a user registers a new account

Authenticated requests

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 related to session management:

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"
    }
    ...
  ]
}

Obtaining tokens

Tokens can be obtained every time the user performs any of the following actions:

  1. When a user signs in
  2. When a user registers an account
  3. When the tokens are refreshed

Refreshing tokens

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:

  1. Send a POST request to /session/token/refresh. The body should contain a JSON paylaod with the refresh_token:

    POST /session/token/refresh HTTP/1.1
    Host: sync.standardnotes.org
    Authorization: Bearer <access token>
    
    {
      "refresh_token": "R_xxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx"
    }
    
  2. The refresh_token is validated on the server. Depending of the circumstances, there should be two outcomes:

    1. The provided refresh_token is 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",
        }
      }
      
    2. The provided refresh_token is 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.

Expiration

Sessions

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 session that remains inactive for 1 year will be terminated, along with all tokens

Tokens

Name Type Expiration
access Short-lived 60 days
refresh Long-lived 1 year
  • A refresh token is of single-use, while an access token can be used as long as it is not expired