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.)