taler-docs

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

049-auth.rst (9876B)


      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: 2026-08-29
     10 :Implementation evidence: merchant (2023-09-06, 2026-08-29), 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 Password changes and recovery
    220 =============================
    221 
    222 A bearer token authorizes access to the account, but it is not sufficient by
    223 itself to replace password authentication.  A merchant changing its own
    224 password must reauthenticate with the current password, which the backend
    225 checks against its stored password hash.  An administrator resetting another
    226 instance's authentication is exempt because the administrative credential is
    227 the authority for that operation.  Deployments may additionally set
    228 ``PASSWORD_CHANGE_MFA`` to require one usable channel from
    229 ``MANDATORY_TAN_CHANNELS`` as a second factor.  If multiple channels are
    230 available, successfully solving any one of them is sufficient.
    231 
    232 Forgotten-password recovery cannot provide the current password.  The public
    233 merchant recovery endpoint therefore requires all channels configured in
    234 ``MANDATORY_TAN_CHANNELS``.  If both SMS and e-mail are configured, both must
    235 be solved; if exactly one is configured, that one challenge is sufficient.  A
    236 merchant backend with no mandatory TAN channel refuses public recovery.
    237 
    238 Definition of Done
    239 ==================
    240 
    241 * [x] spec reviewed
    242 * [x] implemented in merchant backend
    243 * [x] implemented in libeufin-bank
    244 * [x] implemented in the bank webui SPA
    245 * [x] implemented in the merchant backoffice SPA
    246 
    247 
    248 Alternatives
    249 ============
    250 
    251 * use something much closer to OAuth2
    252 
    253   * would be unnecessarly generic and complex
    254 
    255 Session Tokens / Signatures
    256 ---------------------------
    257 
    258 For performance reasons, OAuth 2.0 uses two types of tokens: Short-lived access
    259 tokens and long-lived refresh tokens.  The access tokens can be implemented via
    260 signatures and the long-lived refresh tokens via server-stored tokens.  This
    261 allows to cheaply validate access tokens, while still allowing longer expiration times
    262 for refresh tokens.
    263 
    264 We could do something similar by introducing login and session tokens.  A login
    265 token is a server-stored token.  In addition to being used directly as an
    266 access token, a login token can also be converted to a short-lived session
    267 token.
    268 
    269 Session access tokens should be implemented as "self-encoded tokens", i.e.
    270 as tokens signed by the server without requiring server-side token storage.
    271 Session access tokens should have a rather short maximum expiration.
    272 
    273 The signature should be over ``(username, kind, scope, creation_timestamp, expiry)``.
    274 
    275 To revoke session tokens, the server must store the timestamp of the last
    276 revocation and only accept tokens with a ``creation_timestamp`` larger than the
    277 last revocation timestamp. Individual session tokens cannot be revoked, only
    278 all issued session tokens can be revoked at once.
    279 
    280 However, we decided against doing this because the performance benefits
    281 are not significant enough for us and having multiple token types would
    282 lead to unnecessary complexity.
    283 
    284 Drawbacks
    285 =========
    286 
    287 * still more complex than simple auth tokens or HTTP basic auth
    288 
    289 Discussion / Q&A
    290 ================
    291 
    292 (This should be filled in with results from discussions on mailing lists / personal communication.)