10.49. DD 49: Authentication#
10.49.1. Summary#
This design document specifies a simple authentication framework to be used by multiple Taler components that require authentication.
10.49.2. Motivation#
SPAs currently store the username and password in locals storage (or at least session storage).
There’s also no way to manage auth tokens third parties (e.g. auditors).
10.49.3. Requirements#
simple specification
simple implementation
simple to use
must cover two main use cases:
SPA login
delegating (possibly restricted) access to a third party using a token
10.49.4. Proposed Solution#
We define a token
endpoint that can be used to obtain access tokens from
other forms of authentication, typically HTTP Basic auth.
10.49.4.1. Token Creation#
- POST /${RESOURCE...}/token#
Create an authentification token.
Request:
interface TokenRequest { // Service-defined scope for the token. // Typical scopes would be "readonly" or "readwrite". scope: string; // Server may impose its own upper bound // on the token validity duration duration?: RelativeTime; // Is the token refreshable into a new token during its // validity? // Refreshable tokens effectively provide indefinite // access if they are refreshed in time. // Deprecated, use ":refreshable" suffix in scope instead. refreshable?: boolean; // Optional token description // @since v4 description?: string; }
Response:
- 200 Ok:
The response is a TokenSuccessResponse
Details:
interface TokenSuccessResponse { // Expiration determined by the server. // Can be based on the token_duration // from the request, but ultimately the // server decides the expiration. expiration: Timestamp; // Opque access token. access_token: string; }
10.49.4.2. Token Revocation#
Clients using session tokens log by forgetting the session token.
Tokens can be explicitly revoked by making a DELETE
request on
the token endpoint.
- DELETE /${RESOURCE...}/token#
Invalidate the access token that is being used to make the request. Authentication: The client must authenticate with a valid access token.
10.49.4.3. Token Information#
List existing token informations.
- GET /${RESOURCE...}/tokens#
Request:
- Query Parameters:
delta – Optional. Takes value of the form
N (-N)
, so that at mostN
values strictly older (younger) thanstart
are returned. Defaults to-20
to return the last 20 entries.start – Optional. Row number threshold, see
delta
for its interpretation. Defaults to smallest or biggest row id possible according todelta
sign.
Response:
- 200 OK:
Response is a TokenInfos.
- 204 No content:
No tokens.
Details:
interface TokenInfos { tokens: TokenInfo[]; }
interface TokenInfo { // Time when the token was created. creation_time: Timestamp; // Expiration determined by the server. // Can be based on the token_duration // from the request, but ultimately the // server decides the expiration. expiration: Timestamp; // Service-defined scope for the token. // Typical scopes would be "readonly" or "readwrite". scope: string; // Is the token refreshable into a new token during its // validity? // Refreshable tokens effectively provide indefinite // access if they are refreshed in time. refreshable: boolean; // Optional token description description?: string; // Time when the token was last used. last_access: Timestamp; // Opaque unique ID used for pagination. row_id: Integer; }
10.49.5. Permissions#
Each API request to an endpoint may be associated with a permission.
A permission is a descriptive string, e.g. orders-read
for a GET
request on the endpoint /private/orders
.
Another example would be orders-write
for a POST
or PUT
request on the same endpoint.
If no permission is defined for a request, no access control is enforced.
Each component API must define and document appropriate permissions for its requests.
Permission strings best practice include that read-only access end with the suffix -read
, e.g. orders-read
.
If the access to the endpoint modifies the state it is suffixed with -write
, e.g. orders-write
.
Special permissions may deviate from this.
Two endpoints may use the same permission.
In the API documentaction where the Request to an endpoint is defined, Required permission entry should be added. See the Merchant API for examples.
10.49.6. Scopes#
A scope
is a set of permissions that is associated with a token.
The scope is provided when requesting the token, see TokenRequest.
Default scopes that can be requested in a TokenRequest are or rather must be defined and documented by the component. Here are some examples of possible scopes:
readonly
:*-read
– This wildcard match will grant access to all endpoints protected with a permission that has the-read
suffix.admin
:*
– This matches all permissions, essentially the key to the kingdom.orders-simple
:orders-read,orders-write
– Access to reading and writing orders.orders-full
:orders-read,orders-write,orders-refund
– Likeorders-simple
, but also allows for refunds.
In the merchant component, scopes are currently hard-coded. In the future, additional scopes may be configurable through configuration files and/or default scopes overridden.
10.49.7. Token refresh#
Tokens may be requested to be refreshable.
In older API versions this was achieved by setting the refreshable
field in the TokenRequest.
In recent API versions this is achieved by suffixing the requested scope with :refreshable
, e.g. orders-full:refreshable
.
10.49.8. Definition of Done#
DONE: spec reviewed
DONE: implemented in merchant backend
implemented in libeufin-bank
DONE: implemented in the bank webui SPA
implemented in the merchant backoffice SPA
10.49.9. Alternatives#
use something much closer to OAuth2
would be unnecessarly generic and complex
10.49.9.1. Session Tokens / Signatures#
For performance reasons, OAuth 2.0 uses two types of tokens: Short-lived access tokens and long-lived refresh tokens. The access tokens can be implemented via signatures and the long-lived refresh tokens via server-stored tokens. This allows to cheaply validate access tokens, while still allowing longer expiration times for refresh tokens.
We could do something similar by introducing login and session tokens. A login token is a server-stored token. In addition to being used directly as an access token, a login token can also be converted to a short-lived session token.
Session access tokens should be implemented as “self-encoded tokens”, i.e. as tokens signed by the server without requiring server-side token storage. Session access tokens should have a rather short maximum expiration.
The signature should be over (username, kind, scope, creation_timestamp, expiry)
.
To revoke session tokens, the server must store the timestamp of the last
revocation and only accept tokens with a creation_timestamp
larger than the
last revocation timestamp. Individual session tokens cannot be revoked, only
all issued session tokens can be revoked at once.
However, we decided against doing this because the performance benefits are not significant enough for us and having multiple token types would lead to unnecessary complexity.
10.49.10. Drawbacks#
still more complex than simple auth tokens or HTTP basic auth
10.49.11. Discussion / Q&A#
(This should be filled in with results from discussions on mailing lists / personal communication.)