taler-docs

Documentation for GNU Taler components, APIs and protocols
Log | Files | Refs | README | LICENSE

049-auth.rst (8783B)


      1 DD 49: Authentication
      2 #####################
      3 
      4 :Design status: Accepted
      5 :Implementation status: Implemented
      6 :DD shepherd: TBD
      7 :Historical contributors: Florian Dold, Sebastian, Antoine A, Martin Schanzenbach, Christian Grothoff
      8 :First published: 2023-09-06
      9 :Last substantive change: 2025-06-19
     10 :Implementation evidence: merchant (2023-09-06), libeufin (2024-11-15)
     11 :Normative references: ``core/api-merchant.rst``, ``core/api-corebank.rst``
     12 
     13 .. note::
     14 
     15    Authentication is implemented, but token-refresh syntax is
     16    component-specific.  The component API specifications are normative.
     17 
     18 Summary
     19 =======
     20 
     21 This design document specifies a simple authentication framework to be used by multiple Taler
     22 components that require authentication.
     23 
     24 Motivation
     25 ==========
     26 
     27 SPAs currently store the username and password in locals storage (or at least
     28 session storage).
     29 
     30 There's also no way to manage auth tokens third parties (e.g.
     31 auditors).
     32 
     33 Requirements
     34 ============
     35 
     36 * simple specification
     37 * simple implementation
     38 * simple to use
     39 * must cover two main use cases:
     40 
     41   * SPA login
     42   * delegating (possibly restricted) access to a third party using a token
     43 
     44 Proposed Solution
     45 =================
     46 
     47 We define a ``token`` endpoint that can be used to obtain access tokens from
     48 other forms of authentication, typically HTTP Basic auth.
     49 
     50 Token Creation
     51 --------------
     52 
     53 .. http:post:: /${RESOURCE...}/token
     54 
     55   Create an authentification token.
     56 
     57   **Request:**
     58 
     59   .. ts:def:: TokenRequest
     60 
     61     interface TokenRequest {
     62       // Service-defined scope for the token.
     63       // Typical scopes would be "readonly" or "readwrite".
     64       scope: string;
     65 
     66       // Server may impose its own upper bound
     67       // on the token validity duration
     68       duration?: RelativeTime;
     69 
     70       // Is the token refreshable into a new token during its
     71       // validity?
     72       // Refreshable tokens effectively provide indefinite
     73       // access if they are refreshed in time.
     74       // Deprecated, use ":refreshable" suffix in scope instead.
     75       refreshable?: boolean;
     76 
     77       // Optional token description
     78       // @since v4
     79       description?: string;
     80     }
     81 
     82   **Response:**
     83 
     84   :http:statuscode:`200 Ok`:
     85     The response is a `TokenSuccessResponse`
     86 
     87   **Details:**
     88 
     89   .. ts:def:: TokenSuccessResponse
     90 
     91     interface TokenSuccessResponse {
     92       // Expiration determined by the server.
     93       // Can be based on the token_duration
     94       // from the request, but ultimately the
     95       // server decides the expiration.
     96       expiration: Timestamp;
     97 
     98       // Opque access token.
     99       access_token: string;
    100     }
    101 
    102 Token Revocation
    103 ----------------
    104 
    105 Clients using session tokens log by forgetting the session token.
    106 Tokens can be explicitly revoked by making a ``DELETE`` request on
    107 the token endpoint.
    108 
    109 .. http:delete:: /${RESOURCE...}/token
    110 
    111   Invalidate the access token that is being used to make the request.
    112   **Authentication:**  The client must authenticate
    113   with a valid access token.
    114 
    115 Token Information
    116 -----------------
    117 
    118 List existing token information.
    119 
    120 .. http:get:: /${RESOURCE...}/tokens
    121 
    122   **Request:**
    123 
    124   :query delta: *Optional.*
    125     Takes value of the form ``N (-N)``, so that at most ``N`` values strictly older (younger) than ``start`` are returned.  Defaults to ``-20`` to return the last 20 entries.
    126   :query start: *Optional.*
    127     Row number threshold, see ``delta`` for its interpretation. Defaults to smallest or biggest row id possible according to ``delta`` sign.
    128 
    129   **Response:**
    130 
    131   :http:statuscode:`200 OK`:
    132     Response is a `TokenInfos`.
    133   :http:statuscode:`204 No content`:
    134     No tokens.
    135 
    136   **Details:**
    137 
    138   .. ts:def:: TokenInfos
    139 
    140     interface TokenInfos {
    141       tokens: TokenInfo[];
    142     }
    143 
    144   .. ts:def:: TokenInfo
    145 
    146     interface TokenInfo {
    147       // Time when the token was created.
    148       creation_time: Timestamp;
    149 
    150       // Expiration determined by the server.
    151       // Can be based on the token_duration
    152       // from the request, but ultimately the
    153       // server decides the expiration.
    154       expiration: Timestamp;
    155 
    156       // Service-defined scope for the token.
    157       // Typical scopes would be "readonly" or "readwrite".
    158       scope: string;
    159 
    160       // Is the token refreshable into a new token during its
    161       // validity?
    162       // Refreshable tokens effectively provide indefinite
    163       // access if they are refreshed in time.
    164       refreshable: boolean;
    165 
    166       // Optional token description
    167       description?: string;
    168 
    169       // Time when the token was last used.
    170       last_access: Timestamp;
    171 
    172       // Opaque unique ID used for pagination.
    173       row_id: Integer;
    174     }
    175 
    176 Permissions
    177 ===========
    178 
    179 Each API request to an endpoint **may** be associated with a *permission*.
    180 A permission is a descriptive string, e.g. ``orders-read`` for a ``GET`` request on the endpoint ``/private/orders``.
    181 Another example would be ``orders-write`` for a ``POST`` or ``PUT`` request on the same endpoint.
    182 If no permission is defined for a request, no access control is enforced.
    183 
    184 Each component API **must** define and document appropriate permissions for its requests.
    185 Permission strings best practice include that *read-only* access end with the suffix ``-read``, e.g. ``orders-read``.
    186 If the access to the endpoint modifies the state it is suffixed with ``-write``, e.g. ``orders-write``.
    187 Special permissions may deviate from this.
    188 Two endpoints **may** use the same permission.
    189 
    190 In the API documentaction where the **Request** to an endpoint is defined, **Required permission** entry should be added.
    191 See the Merchant API for examples.
    192 
    193 Scopes
    194 ======
    195 
    196 A ``scope`` is a set of permissions that is associated with a token.
    197 The scope is provided when requesting the token, see `TokenRequest`.
    198 
    199 Default scopes that can be requested in a `TokenRequest` are or rather **must** be defined and documented by the component.
    200 Here are some *examples* of possible scopes:
    201 
    202 * ``readonly``: ``*-read`` -- This wildcard match will grant access to all endpoints protected with a permission that has the ``-read`` suffix.
    203 * ``admin``: ``*`` -- This matches all permissions, essentially the *key to the kingdom*.
    204 * ``orders-simple``: ``orders-read,orders-write`` -- Access to reading and writing orders.
    205 * ``orders-full``: ``orders-read,orders-write,orders-refund`` -- Like ``orders-simple``, but also allows for refunds.
    206 
    207 In the merchant component, scopes are currently hard-coded. In the future, additional scopes may be configurable
    208 through configuration files and/or default scopes overridden.
    209 
    210 Token refresh
    211 =============
    212 
    213 Tokens may be requested to be refreshable.  Merchant APIs express this by
    214 suffixing the requested scope with ``:refreshable``, for example
    215 ``orders-full:refreshable``.  The Core Bank API instead retains the
    216 ``refreshable`` field in its ``TokenRequest``.  Clients must follow the
    217 normative API of the component they use.
    218 
    219 Definition of Done
    220 ==================
    221 
    222 * [x] spec reviewed
    223 * [x] implemented in merchant backend
    224 * [x] implemented in libeufin-bank
    225 * [x] implemented in the bank webui SPA
    226 * [x] implemented in the merchant backoffice SPA
    227 
    228 
    229 Alternatives
    230 ============
    231 
    232 * use something much closer to OAuth2
    233 
    234   * would be unnecessarly generic and complex
    235 
    236 Session Tokens / Signatures
    237 ---------------------------
    238 
    239 For performance reasons, OAuth 2.0 uses two types of tokens: Short-lived access
    240 tokens and long-lived refresh tokens.  The access tokens can be implemented via
    241 signatures and the long-lived refresh tokens via server-stored tokens.  This
    242 allows to cheaply validate access tokens, while still allowing longer expiration times
    243 for refresh tokens.
    244 
    245 We could do something similar by introducing login and session tokens.  A login
    246 token is a server-stored token.  In addition to being used directly as an
    247 access token, a login token can also be converted to a short-lived session
    248 token.
    249 
    250 Session access tokens should be implemented as "self-encoded tokens", i.e.
    251 as tokens signed by the server without requiring server-side token storage.
    252 Session access tokens should have a rather short maximum expiration.
    253 
    254 The signature should be over ``(username, kind, scope, creation_timestamp, expiry)``.
    255 
    256 To revoke session tokens, the server must store the timestamp of the last
    257 revocation and only accept tokens with a ``creation_timestamp`` larger than the
    258 last revocation timestamp. Individual session tokens cannot be revoked, only
    259 all issued session tokens can be revoked at once.
    260 
    261 However, we decided against doing this because the performance benefits
    262 are not significant enough for us and having multiple token types would
    263 lead to unnecessary complexity.
    264 
    265 Drawbacks
    266 =========
    267 
    268 * still more complex than simple auth tokens or HTTP basic auth
    269 
    270 Discussion / Q&A
    271 ================
    272 
    273 (This should be filled in with results from discussions on mailing lists / personal communication.)