github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/docs/auth.md (about) 1 [Table of contents](README.md#table-of-contents) 2 3 # Authentication and access delegations 4 5 ## Introduction 6 7 In this document, we will cover how to protect the usage of the cozy-stack. When 8 the cozy-stack receives a request, it checks that the request is authorized, and 9 if yes, it processes it and answers it. 10 11 ## What about OAuth2? 12 13 OAuth2 is about delegating an access to resources on a server to another party. 14 It is a framework, not a strictly defined protocol, for organizing the 15 interactions between these 4 actors: 16 17 - the resource owner, the "user" that can click on buttons 18 - the client, the website or application that would like to access the 19 resources 20 - the authorization server, whose role is limited to give tokens but is 21 central in OAuth2 interactions 22 - the resources server, the server that controls the resources. 23 24 For cozy, both the authorization server and the resources server roles are 25 played by the cozy-stack. The resource owner is the owner of a cozy instance. 26 The client can be the cozy-desktop app, cozy-mobile, or many other applications. 27 28 OAuth2, and its extensions, is a large world. At its core, there is 2 things: 29 letting the client get a token issued by the authorization server, and using 30 this token to access to the resources. OAuth2 describe 4 flows, called grant 31 types, for the first part: 32 33 - Authorization code 34 - Implicit grant type 35 - Client credentials grant type 36 - Resource owner credentials grant type. 37 38 On cozy, only the most typical one is used: authorization code. To start this 39 flow, the client must have a `client_id` and `client_secret`. The Cozy stack 40 implements the OAuth2 Dynamic Client Registration Protocol (an extension to 41 OAuth2) to allow the clients to obtain them. 42 43 OAuth2 has also 3 ways to use a token: 44 45 - in the query-string (even if the spec does not recommended it) 46 - in the POST body 47 - in the HTTP Authorization header. 48 49 On cozy, only the HTTP header is supported. 50 51 OAuth2 has a lot of assumptions. Let's see some of them and their consequences 52 on Cozy: 53 54 - TLS is very important to secure the communications. in OAuth 1, there was a 55 mechanism to sign the requests. But it was very difficult to get it right 56 for the developers and was abandonned in OAuth2, in favor of using TLS. The 57 Cozy instance are already accessible only in HTTPS, so there is nothing 58 particular to do for that. 59 60 - There is a principle called TOFU, Trust On First Use. It said that if the 61 user will give his permission for delegating access to its resources when 62 the client will try to access them for the first time. Later, the client 63 will be able to keep accessing them even if the user is no longer here to 64 give his permissions. 65 66 - The client can't make the assumptions about when its tokens will work. The 67 tokens have no meaning for him (like cookies in a browser), they are just 68 something it got from the authorization server and can send with its 69 request. The access token can expire, the user can revoke them, etc. 70 71 - OAuth 2.0 defines no cryptographic methods. But a developer that want to use 72 it will have to put her hands in that. 73 74 If you want to learn OAuth 2 in details, I recommend the 75 [OAuth 2 in Action book](https://www.manning.com/books/oauth-2-in-action). 76 77 ## The cozy stack as an authorization server 78 79 In general, the cozy stack manages the authentication itself. This is what is 80 described below. In some special cases, an integration with other softwares can 81 be mandatory: this is possible to configure via 82 [delegated authentication](./delegated-auth.md). 83 84 ### GET /auth/login 85 86 Display a form with a password field to let the user authenticates herself to 87 the cozy stack. 88 89 This endpoint accepts a `redirect` parameter. If the user is already logged in, 90 she will be redirected immediately. Else, the parameter will be transfered in 91 the POST. This parameter can only contain a link to an application installed on 92 the cozy (thus to a subdomain of the cozy instance). To protect against stealing 93 authorization code with redirection, the fragment is always overriden: 94 95 ```http 96 GET /auth/login?redirect=https://contacts.cozy.example.org/foo?bar#baz HTTP/1.1 97 Host: cozy.example.org 98 Cookie: ... 99 ``` 100 101 **Note**: the redirect parameter should be URL-encoded. We haven't done that to 102 make it clear what the path (`foo`), the query-string (`bar`), and the fragment 103 (`baz`) are. 104 105 ```http 106 HTTP/1.1 302 Moved Temporarily 107 Location: https://contacts.cozy.example.org/foo?bar# 108 ``` 109 110 If the `redirect` parameter is invalid, the response will be `400 Bad Request`. 111 Same for other parameters, the redirection will happen only on success (even if 112 OAuth2 says the authorization server can redirect on errors, it's very 113 complicated to do it safely, and it is better to avoid this trap). 114 115 ### POST /auth/login 116 117 After the user has typed her passphrase and clicked on `Login`, a request is 118 made to this endpoint. 119 120 The `redirect` parameter is passed inside the body. If it is missing, the 121 redirection will be made against the default target: the home application of 122 this cozy instance. The redirect can be a full URL (like 123 `http://cozy-drive.example.org/#/folder`), or just a slug+path+hash (like 124 `drive/#/folder`). 125 126 ```http 127 POST /auth/login HTTP/1.1 128 Host: cozy.example.org 129 Content-Type: application/x-www-form-urlencoded 130 131 passphrase=p4ssw0rd&redirect=https%3A%2F%2Fcontacts.cozy.example.org 132 ``` 133 134 ```http 135 HTTP/1.1 302 Moved Temporarily 136 Set-Cookie: ... 137 Location: https://contacts.cozy.example.org/foo 138 ``` 139 140 When two-factor authentication (2FA) authentication is activated, this endpoint 141 will not directly sent a redirection after this first passphrase step. In such 142 case, a `200 OK` response is sent along with a token value in the response 143 (either in JSON if requested or directly in a new HTML form). 144 145 Along with this token, a 2FA passcode is sent to the user via another transport 146 (email for instance, depending on the user's preferences). Another request 147 should be sent to `/auth/twofactor` with a valid pair `(token, passcode)`, 148 ensuring that the user correctly entered its passphrase _and_ received a fresh 149 passcode by another mean. 150 151 ### POST /auth/twofactor 152 153 ```http 154 POST /auth/twofactor HTTP/1.1 155 Host: cozy.example.org 156 Content-Type: application/x-www-form-urlencoded 157 158 two-factor-token=123123123123&two-factor-passcode=678678&redirect=https%3A%2F%2Fcontacts.cozy.example.org 159 ``` 160 161 ```http 162 HTTP/1.1 302 Moved Temporarily 163 Set-Cookie: ... 164 Location: https://contacts.cozy.example.org/foo 165 ``` 166 167 ### POST /auth/login/flagship 168 169 This endpoint is similar to `POST /auth/login`, but it allows the flagship app 170 to also obtain OAuth access and register tokens without having to make the 171 OAuth dance (which can be awkward for the user). 172 173 #### Request 174 175 ```http 176 POST /auth/login/flagship HTTP/1.1 177 Host: alice.example.com 178 Content-Type: application/json 179 ``` 180 181 ```json 182 { 183 "passphrase": "4f58133ea0f415424d0a856e0d3d2e0cd28e4358fce7e333cb524729796b2791", 184 "client_id": "64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3", 185 "client_secret": "eyJpc3Mi[...omitted for brevity...]" 186 } 187 ``` 188 189 #### Response 190 191 ```http 192 HTTP/1.1 200 OK 193 Content-Type: application/json 194 ``` 195 196 ```json 197 { 198 "access_token": "OWY0MjNjMGEtOTNmNi0xMWVjLWIyZGItN2I5YjgwNmRjYzBiCg", 199 "token_type": "bearer", 200 "refresh_token": "YTUwMjcyYjgtOTNmNi0xMWVjLWE4YTQtZWJhMzlmMTAwMWJiCg", 201 "scope": "*" 202 } 203 ``` 204 205 **Note:** if two-factor authentication is enabled on the Cozy, an email 206 will be sent to the user with a code, and this request will return: 207 208 ```http 209 HTTP/1.1 401 Unauthorized 210 Content-Type: application/json 211 ``` 212 213 ```json 214 { 215 "two_factor_token": "123123123123" 216 } 217 ``` 218 219 Then, the client can retry by sending the two-factor token and code: 220 221 ```json 222 { 223 "passphrase": "4f58133ea0f415424d0a856e0d3d2e0cd28e4358fce7e333cb524729796b2791", 224 "client_id": "64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3", 225 "client_secret": "eyJpc3Mi[...omitted for brevity...]", 226 "two_factor_token": "123123123123", 227 "two_factor_code": "123456" 228 } 229 ``` 230 231 **Note:** if the two-factor authentication is enabled, and the cloudery has 232 already verified the email address, a parameter `email_verified_code` can be sent 233 to skip another 2FA code sent by mail. 234 235 236 ```json 237 { 238 "passphrase": "4f58133ea0f415424d0a856e0d3d2e0cd28e4358fce7e333cb524729796b2791", 239 "client_id": "64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3", 240 "client_secret": "eyJpc3Mi[...omitted for brevity...]", 241 "email_verified_code": "987456321" 242 } 243 ``` 244 245 **Note:** if the OAuth client has not been certified as the flagship app, 246 this request will return: 247 248 ```http 249 HTTP/1.1 202 Accepted 250 Content-Type: application/json 251 ``` 252 253 ```json 254 { 255 "session_code": "ZmY4ODI3NGMtOTY1Yy0xMWVjLThkMDgtMmI5M2" 256 } 257 ``` 258 259 The `session_code` can be put in the query string while opening the OAuth 260 authorize page. It will be used to open the session, and let the user type the 261 6-digits code they have received by mail to confirm that they want to use this 262 app as the flagship app. 263 264 ### DELETE /auth/login 265 266 This can be used to log-out the user. An app token must be passed in the 267 `Authorization` header, to protect against CSRF attack on this (this can part of 268 bigger attacks like session fixation). 269 270 ```http 271 DELETE /auth/login HTTP/1.1 272 Host: cozy.example.org 273 Cookie: seesioncookie.... 274 Authorization: Bearer app-token 275 ``` 276 277 ### DELETE /auth/login/others 278 279 This can be used to log-out all active sessions except the one used by the 280 request. This allow to disconnect any other users currenctly authenticated on 281 the system. An app token must be passed in the `Authorization` header, to 282 protect against CSRF attack on this (this can part of bigger attacks like 283 session fixation). 284 285 ```http 286 DELETE /auth/login/others HTTP/1.1 287 Host: cozy.example.org 288 Cookie: seesioncookie.... 289 Authorization: Bearer app-token 290 ``` 291 292 ### POST /auth/magic_link 293 294 If the authentication via magic link is enabled on this instance, this endpoint 295 will send an email to the user with a magic link. If the user clicks on this 296 link, they will be authenticated on the Cozy. 297 298 ### GET /auth/magic_link?code=... 299 300 When the user has received an email with a magic link, the link goes to the 301 endpoint, where the user will be allowed to enter the Cozy. 302 303 ### POST /auth/magic_link/twofactor 304 305 When two-factor authentication is enabled on a Cozy, this endpoint can be used 306 to create a session. 307 308 ### POST /auth/magic_link/flagship 309 310 This endpoint allows the flagship app to also obtain OAuth access and register 311 tokens without having to make the OAuth dance (which can be awkward for the 312 user). It requires a code sent by email to the user. 313 314 #### Request 315 316 ```http 317 POST /auth/magic_link/flagship HTTP/1.1 318 Host: alice.example.com 319 Content-Type: application/json 320 ``` 321 322 ```json 323 { 324 "magic_code": "ODFhNzkxYTAtYjZiYi0wMTNiLTE1YzQtMThjMDRkYWJhMzI2", 325 "client_id": "64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3", 326 "client_secret": "eyJpc3Mi[...omitted for brevity...]" 327 } 328 ``` 329 330 #### Response 331 332 ```http 333 HTTP/1.1 200 OK 334 Content-Type: application/json 335 ``` 336 337 ```json 338 { 339 "access_token": "OWY0MjNjMGEtOTNmNi0xMWVjLWIyZGItN2I5YjgwNmRjYzBiCg", 340 "token_type": "bearer", 341 "refresh_token": "YTUwMjcyYjgtOTNmNi0xMWVjLWE4YTQtZWJhMzlmMTAwMWJiCg", 342 "scope": "*" 343 } 344 ``` 345 346 **Note:** if two-factor authentication is enabled on the Cozy, an email 347 will be sent to the user with a code, and this request will return: 348 349 ```http 350 HTTP/1.1 401 Unauthorized 351 Content-Type: application/json 352 ``` 353 354 ```json 355 { 356 "error": "passphrase is required as second authentication factor" 357 } 358 ``` 359 360 Then, the client can retry by sending the two-factor token and code: 361 362 ```json 363 { 364 "magic_code": "ODFhNzkxYTAtYjZiYi0wMTNiLTE1YzQtMThjMDRkYWJhMzI2", 365 "client_id": "64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3", 366 "client_secret": "eyJpc3Mi[...omitted for brevity...]", 367 "passphrase": "4f58133ea0f415424d0a856e0d3d2e0cd28e4358fce7e333cb524729796b2791" 368 } 369 ``` 370 371 **Note:** if the OAuth client has not been certified as the flagship app, 372 this request will return: 373 374 ```http 375 HTTP/1.1 202 Accepted 376 Content-Type: application/json 377 ``` 378 379 ```json 380 { 381 "session_code": "ZmY4ODI3NGMtOTY1Yy0xMWVjLThkMDgtMmI5M2" 382 } 383 ``` 384 385 The `session_code` can be put in the query string while opening the OAuth 386 authorize page. It will be used to open the session, and let the user type the 387 6-digits code they have received by mail to confirm that they want to use this 388 app as the flagship app. 389 390 ### GET /auth/passphrase_reset 391 392 Display a form for the user to reset its password, in case he has forgotten it 393 for example. If the user is connected, he won't be shown this form and he will 394 be directly redirected to his cozy. 395 396 This endpoint accepts a `hideBackButton` parameter. If this parameter is present 397 and set to `true` then the passphrase reset page won't display any button to go 398 back to the login page. 399 This is useful when this page is opened in a different context from the one in 400 which the login page was opened (e.g. a browser vs a mobile native application). 401 402 It is also possible to use `from=settings` parameter in the query-string, to go 403 back to the settings app after the password has been reset. It is useful when 404 the user wants to change their email address, as the process for changing this 405 address requires the password. 406 407 ```http 408 GET /auth/passphrase_reset?hideBackButton=true HTTP/1.1 409 Host: cozy.example.org 410 Content-Type: text/html 411 Cookie: ... 412 ``` 413 414 ### POST /auth/hint 415 416 Send the password hint by email. 417 418 ```http 419 POST /auth/hint HTTP/1.1 420 Host: cozy.example.org 421 ``` 422 423 ### POST /auth/onboarding/resend 424 425 Resend the activation link by email to finalize the onboarding. 426 427 ```http 428 POST /auth/onboarding/resend HTTP/1.1 429 Host: cozy.example.org 430 ``` 431 432 ### POST /auth/passphrase_reset 433 434 After the user has clicked on the reset button of the passphrase reset form, it 435 will execute a request to this endpoint. 436 437 This endpoint will create a token for the user to actually renew his passphrase. 438 The token has a short-live duration of about 15 minutes. After the token is 439 created, it is sent to the user on its mailbox. 440 441 This endpoint will redirect the user on the login form page. 442 443 ```http 444 POST /auth/passphrase_reset HTTP/1.1 445 Host: cozy.example.org 446 Content-Type: application/x-www-form-urlencoded 447 448 csrf_token=123456890 449 ``` 450 451 ### GET /auth/passphrase_renew 452 453 Display a form for the user to enter a new password. This endpoint should be 454 used with a `token` query parameter. This token makes sure that the user has 455 actually reset its passphrase and should have been sent via its mailbox. 456 457 ```http 458 GET /auth/passphrase_renew?token=123456789 HTTP/1.1 459 Host: cozy.example.org 460 Content-Type: text/html 461 Cookie: ... 462 ``` 463 464 ### POST /auth/passphrase_renew 465 466 After the user has entered its new passphrase in the renew passphrase form, a 467 request is made to this endpoint to renew the passphrase. 468 469 This endpoint requires a valid token to actually work. In case of a success, the 470 user is redirected to the login form. 471 472 ```http 473 POST /auth/passphrase_reset HTTP/1.1 474 Host: cozy.example.org 475 Content-Type: application/x-www-form-urlencoded 476 477 csrf_token=123456890&passphrase_reset_token=123456789&passphrase=mynewpassphrase 478 ``` 479 480 #### Parameters 481 482 | Form parameter | Description | 483 | ---------------------- | ----------------------------------------- | 484 | passphrase_reset_token | the token to authenticate the request | 485 | csrf_token | the token to protect against CSRF attacks | 486 | passphrase | the new password | 487 | hint | the hint to find again the password | 488 | iterations | the number of PBKDF2 iterations | 489 | key | the encrypted master key for bitwarden | 490 | public_key | the public key for the cozy organization | 491 | private_key | the private key for the cozy organization | 492 493 ### GET /auth/passphrase 494 495 This page renders a form to set the password for an onboarding instance. This 496 endpoint expects a valid `registerToken` parameter. 497 498 In case of success, the instance is marked as onboarded and the user is 499 redirected to his home. 500 501 If the instance is already onboarded, the user is redirected to his home. 502 503 It is also possible to give a `redirection` parameter to redirect the user to 504 another application. 505 506 ```http 507 GET /auth/passphrase/?registerToken=e0fbe2c5b90cdcdd9b3487b48b480e0b&redirection=drive/%23/files HTTP/1.1 508 Host: cozy.example.org 509 Content-Type: text/html 510 ``` 511 512 ### GET /auth/confirm 513 514 An application can ask the user to re-authenticate them-selves before making an 515 important action (like erasing a pin code). To do that, the application will 516 sent the user to this page where the stack will show a form. 517 518 Two parameters in the query string can be sent: 519 520 - `state` (mandatory), which can be seen as an identifier for the confirmation 521 - `redirect` (optional), where the user will be redirected after the confirmation. 522 523 ```http 524 GET /auth/confirm?state=51814f30-5818-0139-9348-543d7eb8149c&redirect=http://banks.cozy.localhost:8080/ HTTP/1.1 525 ``` 526 527 The application can know the user has confirmed their identity by subscribing 528 to a real-time event or by looking at the URL after the redirection. The URL 529 must contain the state given by the app, and a code that can be checked by 530 calling `POST /auth/confirm/code` (see below). 531 532 ### POST /auth/confirm 533 534 Send the hashed password for confirming the authentication. 535 536 #### Redirection 537 538 ```http 539 HTTP/1.1 302 Moved Temporarily 540 Location: http://banks.cozy.localhost:8080/?state=51814f30-5818-0139-9348-543d7eb8149c&code=543d7eb8149c 541 ``` 542 543 #### Real-time via websockets 544 545 If it succeeds, a real-time event will be sent: 546 547 ``` 548 client > {"method": "AUTH", 549 "payload": "xxAppOrAuthTokenxx="} 550 client > {"method": "SUBSCRIBE", 551 "payload": {"type": "io.cozy.auth.confirmations"}} 552 server > {"event": "CREATED", 553 "payload": {"id": "51814f30-5818-0139-9348-543d7eb8149c", 554 "type": "io.cozy.auth.confirmations"}} 555 ``` 556 557 ### GET /auth/confirm/:code 558 559 Send the code from the URL to check that the user has really confirmed their 560 identity (and not just typed the URL them-self). 561 562 ```http 563 GET /auth/confirm/543d7eb8149c HTTP/1.1 564 ``` 565 566 The response will be a 204 No Content if the code is valid (and a 401 else). 567 568 ### POST /auth/register 569 570 This route is used by OAuth2 clients to dynamically register them-selves. 571 572 See 573 [OAuth 2.0 Dynamic Client Registration Protocol](https://tools.ietf.org/html/rfc7591) 574 for the details. 575 576 The client must send a JSON request, with at least: 577 578 - `redirect_uris`, an array of strings with the redirect URIs that the client 579 will use in the authorization flow 580 - `client_name`, human-readable string name of the client to be presented to 581 the end-user during authorization 582 - `software_id`, an identifier of the software used by the client (it should 583 remain the same for all instances of the client software, whereas 584 `client_id` varies between instances). 585 586 It can also send the optional fields: 587 588 - `client_kind` (possible values: web, desktop, mobile, browser, etc.) 589 - `client_uri`, URL string of a web page providing information about the 590 client 591 - `logo_uri`, to display an icon to the user in the authorization flow 592 - `policy_uri`, URL string that points to a human-readable privacy policy 593 document that describes how the deployment organization collects, uses, 594 retains, and discloses personal data 595 - `software_version`, a version identifier string for the client software. 596 - `notification_platform`, to activate notifications on the associated device, 597 this field specify the platform used to send notifications: 598 - `"android"`: for Android devices with notifications via Firebase Cloud 599 Messaging 600 - `"ios"`: for iOS devices with notifications via Firebase Cloud 601 Messaging or APNS/2 602 - `"huawei"`: for huawei devices with Push Kit 603 - `notification_device_token`, the token used to identify the mobile device 604 for notifications. 605 606 The server gives to the client the previous fields and these informations: 607 608 - `client_id` 609 - `client_secret` 610 - `registration_access_token` 611 612 Example: 613 614 ```http 615 POST /auth/register HTTP/1.1 616 Host: cozy.example.org 617 Content-Type: application/json 618 Accept: application/json 619 ``` 620 621 ```json 622 { 623 "redirect_uris": ["https://client.example.org/oauth/callback"], 624 "client_name": "Client", 625 "software_id": "github.com/example/client", 626 "software_version": "2.0.1", 627 "client_kind": "web", 628 "client_uri": "https://client.example.org/", 629 "logo_uri": "https://client.example.org/logo.svg", 630 "policy_uri": "https://client/example.org/policy" 631 } 632 ``` 633 634 ```http 635 HTTP/1.1 201 Created 636 Content-Type: application/json 637 ``` 638 639 ```json 640 { 641 "client_id": "64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3", 642 "client_secret": "eyJpc3Mi[...omitted for brevity...]", 643 "client_secret_expires_at": 0, 644 "registration_access_token": "J9l-ZhwP[...omitted for brevity...]", 645 "grant_types": ["authorization_code", "refresh_token"], 646 "response_types": ["code"], 647 "redirect_uris": ["https://client.example.org/oauth/callback"], 648 "client_name": "Client", 649 "software_id": "github.com/example/client", 650 "software_version": "2.0.1", 651 "client_kind": "web", 652 "client_uri": "https://client.example.org/", 653 "logo_uri": "https://client.example.org/logo.svg", 654 "policy_uri": "https://client/example.org/policy" 655 } 656 ``` 657 658 #### Linked applications 659 660 Some OAuth applications are a mobile or desktop version of a Cozy webapp. For 661 them, it's possible to use a special `software_id` to make a link between the 662 mobile/desktop application and the webapp. The `software_id` must be in a 663 `registry://slug` format, like `registry://drive` for Cozy-Drive for example. 664 When it is the case, the mobile/desktop will share its permissions with the 665 webapp. It means several things: 666 667 - The mobile/desktop app will have the same permissions that the linked webapp. 668 - When a sharing by link is done in the mobile/desktop application, the linked 669 webapp will be able to revoke it later, and vice versa. 670 - When the user accepts to give access to its Cozy to the mobile/desktop app, 671 the linked webapp will be installed on the Cozy if it was not already the 672 case. 673 - When the linked webapp is uninstalled, the right to access the Cozy for the 674 mobile/desktop app will be revoked. 675 676 ### GET /auth/register/:client-id 677 678 This route is used by the clients to get informations about them-selves. The 679 client has to send its registration access token to be able to use this 680 endpoint. 681 682 See 683 [OAuth 2.0 Dynamic Client Registration Management Protocol](https://tools.ietf.org/html/rfc7592) 684 for more details. 685 686 ```http 687 GET /auth/register/64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3 HTTP/1.1 688 Host: cozy.example.org 689 Accept: application/json 690 Authorization: Bearer J9l-ZhwP... 691 ``` 692 693 ```http 694 HTTP/1.1 201 Created 695 Content-Type: application/json 696 ``` 697 698 ```json 699 { 700 "client_id": "64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3", 701 "client_secret": "eyJpc3Mi[...omitted for brevity...]", 702 "client_secret_expires_at": 0, 703 "grant_types": ["authorization_code", "refresh_token"], 704 "response_types": ["code"], 705 "redirect_uris": ["https://client.example.org/oauth/callback"], 706 "client_name": "Client", 707 "software_id": "github.com/example/client", 708 "software_version": "2.0.1", 709 "client_kind": "web", 710 "client_uri": "https://client.example.org/", 711 "logo_uri": "https://client.example.org/logo.svg", 712 "policy_uri": "https://client/example.org/policy" 713 } 714 ``` 715 716 ### PUT /auth/register/:client-id 717 718 This route is used by the clients to update informations about them-selves. The 719 client has to send its registration access token to be able to use this 720 endpoint. 721 722 **Note:** the client can ask to change its `client_secret`. To do that, it must 723 send the current `client_secret`, and the server will respond with the new 724 `client_secret`. 725 726 ```http 727 PUT /auth/register/64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3 HTTP/1.1 728 Host: cozy.example.org 729 Accept: application/json 730 Content-Type: application/json 731 Authorization: Bearer J9l-ZhwP... 732 ``` 733 734 ```json 735 { 736 "client_id": "64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3", 737 "client_secret": "eyJpc3Mi[...omitted for brevity...]", 738 "redirect_uris": ["https://client.example.org/oauth/callback"], 739 "client_name": "Client", 740 "software_id": "github.com/example/client", 741 "software_version": "2.0.2", 742 "client_kind": "web", 743 "client_uri": "https://client.example.org/", 744 "logo_uri": "https://client.example.org/client-logo.svg", 745 "policy_uri": "https://client/example.org/policy", 746 "notification_platform": "android", 747 "notification_device_token": "XXXXxxxx..." 748 } 749 ``` 750 751 ```http 752 HTTP/1.1 200 OK 753 Content-Type: application/json 754 ``` 755 756 ```json 757 { 758 "client_id": "64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3", 759 "client_secret": "IFais2Ah[...omitted for brevity...]", 760 "client_secret_expires_at": 0, 761 "grant_types": ["authorization_code", "refresh_token"], 762 "response_types": ["code"], 763 "redirect_uris": ["https://client.example.org/oauth/callback"], 764 "client_name": "Client", 765 "software_id": "github.com/example/client", 766 "software_version": "2.0.2", 767 "client_kind": "web", 768 "client_uri": "https://client.example.org/", 769 "logo_uri": "https://client.example.org/client-logo.svg", 770 "policy_uri": "https://client/example.org/policy" 771 } 772 ``` 773 774 ### DELETE /auth/register/:client-id 775 776 This route is used by the clients to unregister them-selves. The client has to 777 send its registration access token to be able to use this endpoint. 778 779 ```http 780 DELETE /auth/register/64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3 HTTP/1.1 781 Host: cozy.example.org 782 Authorization: Bearer J9l-ZhwP... 783 ``` 784 785 ```http 786 HTTP/1.1 204 No Content 787 ``` 788 789 ### POST /auth/clients/:client-id/challenge 790 791 This route can be used to start the process for certifying that an app is 792 really what it tells to be by using the android/iOS APIs 793 (PlayIntegrity/SafetyNet/AppleAttestation). It returns a nonce that must be 794 used in the certificate. 795 796 The client must send its registration access token to use this endpoint. 797 798 ```http 799 POST /auth/clients/64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3/challenge HTTP/1.1 800 Host: cozy.example.org 801 Authorization: Bearer J9l-ZhwP... 802 ``` 803 804 ```http 805 HTTP/1.1 201 Created 806 Content-Type: application/json 807 ``` 808 809 ```json 810 { 811 "nonce": "MmE3OTM1ZDItNWY0ZC0xMWVjLTg3NT" 812 } 813 ``` 814 815 ### POST /auth/clients/:client-id/attestation 816 817 This route can be used to finish the process for certifying that an app is 818 really what it tells to be by using the android/iOS APIs. The client can send 819 its attestation. 820 821 ```http 822 POST /auth/clients/64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3/attestation HTTP/1.1 823 Host: cozy.example.org 824 Content-Type: application/json 825 ``` 826 827 ```json 828 { 829 "platform": "android", 830 "challenge": "MmE3OTM1ZDItNWY0ZC0xMWVjLTg3NT", 831 "attestation": "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk" 832 } 833 ``` 834 835 Note: the `platform` parameter can be `"android"` or `"ios"`. For `ios`, a 836 `"keyId"` parameter is also required. For `android`, the `"issuer"` can be 837 `"playintegrity"` to use the Play Integrity API instead of the SafetyNet API. 838 839 ```http 840 HTTP/1.1 204 No Content 841 ``` 842 843 ### POST /auth/clients/:client-id/flagship 844 845 This route can be used to send a 6-digits code to manually certify a client as 846 belonging to the flagship app. 847 848 ```http 849 POST /auth/clients/64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3/flagship HTTP/1.1 850 Host: cozy.example.org 851 Content-Type: application/x-www-form-urlencoded 852 853 code=123456&token=123123123123123 854 ``` 855 856 ```http 857 HTTP/1.1 204 No Content 858 ``` 859 860 ### GET /auth/authorize 861 862 When an OAuth2 client wants to get access to the data of the cozy owner, it 863 starts the OAuth2 dance with this step. The user is shown what the client asks 864 and has an accept button if she is OK with that. 865 866 In case a limit has been set on the Cozy to the number of user-connected OAuth 867 clients, and this limit has been reached already, the user will be presented a 868 screen requesting to either remove some existing clients or, if enabled, 869 increase the limit (e.g. by subscribing to a plan with a greater limit). Once 870 the number of connected clients is brought back under the limit, the OAuth flow 871 will resume and the permissions screen will be displayed. 872 873 The parameters are: 874 875 - `client_id`, that identify the client 876 - `redirect_uri`, it has to be exactly the same as the one used in 877 registration 878 - `state`, it's a protection against CSRF on the client (a random string 879 generated by the client, that it can check when the user will be redirected 880 with the authorization code. It can be used as a key in local storage for 881 storing a state in a SPA). 882 - `response_type`, only `code` is supported 883 - `scope`, a space separated list of the [permissions](permissions.md) asked 884 (like `io.cozy.files:GET` for read-only access to files). 885 886 ```http 887 GET /auth/authorize?client_id=oauth-client-1&response_type=code&scope=io.cozy.files%3AGET%20io.cozy.contacts&state=Eh6ahshepei5Oojo&redirect_uri=https%3A%2F%2Fclient.org%2F HTTP/1.1 888 Host: cozy.example.org 889 ``` 890 891 **Note** we warn the user that he is about to share his data with an application 892 which only the callback URI is guaranteed. 893 894 #### PKCE extension 895 896 To improve security, the client can use the [PKCE for OAuth 897 2](https://oauth.net/2/pkce/). In that case, two additional parameters must be 898 send to `GET /auth/authorize`: 899 900 - `code_challenge`: the client creates a `code_verifier`, and then derive the 901 `code_challenge` from it. 902 - `code_challenge_method`: it must be `S256` (the only supported method). 903 904 As a reminder, the relation between `code_verifier` and `code_challenge` is the 905 following: 906 907 ``` 908 code_challenge = BASE64URL-ENCODE(SHA256(code_verifier)) 909 ``` 910 911 And, the `code_verifier` parameter must be sent to `POST /auth/access_token` 912 (see below). 913 914 ### POST /auth/authorize 915 916 When the user accepts, her browser send a request to this endpoint: 917 918 ```http 919 POST /auth/authorize HTTP/1.1 920 Host: cozy.example.org 921 Content-Type: application/x-www-form-urlencoded 922 923 state=Eh6ahshepei5Oojo&client_id=oauth-client-1&scope=io.cozy.files%3AGET%20io.cozy.contacts&csrf_token=johw6Sho&response_type=code&redirect_uri=https%3A%2F%2Fclient.org%2F 924 ``` 925 926 **Note**: this endpoint is protected against CSRF attacks. 927 928 The user is then redirected to the original client, with an access code in the 929 URL: 930 931 ```http 932 HTTP/1.1 302 Moved Temporarily 933 Location: https://client.org/?state=Eh6ahshepei5Oojo&code=Aih7ohth# 934 ``` 935 936 ### GET /auth/authorize/sharing & POST /auth/authorize/sharing 937 938 They are similar to `/auth/authorize`: they also make the user accept an OAuth 939 thing, but it is specialized for sharing. They are a few differences, like the 940 scope format (sharing rules, not permissions) and the redirection after the 941 POST (with `sharing=<sharing-id>` in the query string). 942 943 ### GET /auth/authorize/move & POST /auth/authorize/move 944 945 They are similar to `/auth/authorize`, but instead of a page that lists the 946 permissions, the user will be asked to type their password to confirm the 947 action (even if they are already logged-in). If the 2FA is activated, the code 948 will be asked too. This strong action seems adequate for authorizing to erase 949 the data in the Cozy before importing data from another Cozy. 950 951 #### Request GET 952 953 ```http 954 GET /auth/authorize/move?state=8d560d60&client_id=oauth-client-2&redirect_uri=https://move.cozycloud.cc/callback/target HTTP/1.1 955 Server: target.cozy.example 956 ``` 957 958 #### Response GET 959 960 ```http 961 HTTP/1.1 200 OK 962 Content-Type: application/html 963 ``` 964 965 #### Request POST 966 967 ```http 968 POST /auth/authorize/move HTTP/1.1 969 Server: target.cozy.example 970 Content-Type: application/x-www-form-urlencoded 971 972 passphrase=hashed&state=8d560d60&client_id=oauth-client-2&csrf_token=johw6Sho&redirect_uri=https%3A%2F%2Fmove.cozycloud.cc%2Fcallback%2Ftarget 973 ``` 974 975 #### Response POST 976 977 ```http 978 HTTP/1.1 200 OK 979 Content-Type: application/json 980 ``` 981 982 ```json 983 { 984 "redirect": "https://move.cozycloud.cc/callback/target?code=543d7eb8149c&used=123456"a=5000000&state=8d560d60&vault=true" 985 } 986 ``` 987 988 ### POST /auth/access_token 989 990 Now, the client can check that the state is correct, and if it is the case, ask 991 for an `access_token`. It can use this route with the `code` given above. 992 993 This endpoint is also used to refresh the access token, by sending the 994 `refresh_token` instead of the `code`. 995 996 The parameters are: 997 998 - `grant_type`, with `authorization_code` or `refresh_token` as value 999 - `code` or `refresh_token`, depending on which grant type is used 1000 - `client_id` 1001 - `client_secret` 1002 1003 Example: 1004 1005 ```http 1006 POST /auth/access_token HTTP/1.1 1007 Host: cozy.example.org 1008 Content-Type: application/x-www-form-urlencoded 1009 Accept: application/json 1010 1011 grant_type=authorization_code&code=Aih7ohth&client_id=oauth-client-1&client_secret=Oung7oi5 1012 ``` 1013 1014 ```http 1015 HTTP/1.1 200 OK 1016 Content-Type: application/json 1017 ``` 1018 1019 ```json 1020 { 1021 "access_token": "ooch1Yei", 1022 "token_type": "bearer", 1023 "refresh_token": "ui0Ohch8", 1024 "scope": "io.cozy.files:GET io.cozy.contacts" 1025 } 1026 ``` 1027 1028 ### POST /auth/session_code 1029 1030 This endpoint can be used by the flagship application in order to create a 1031 session code: this code can be added to the URL of a cozy application (in the 1032 query string, as `session_code`) to create a session. The flagship can create 1033 this code with its access token, and then use it in a webview to avoid the 1034 reauthentication of the user. It can also create the code with the hashed 1035 passphrase (and 2FA if needed) to create a session for the authorize page. 1036 1037 Note that the difference between a `session_code` and a `magic_code` (code in a 1038 magic link sent by email) is the behavior when two-factor authentication is 1039 enabled. The `session_code` will open the session while the `magic_code` will 1040 require the password for that. 1041 1042 #### Request (access token variant) 1043 1044 ```http 1045 POST /auth/session_code HTTP/1.1 1046 Host: cozy.example.org 1047 Accept: application/json 1048 Authorization: Bearer eyJpc3Mi... 1049 ``` 1050 1051 #### Request (passphrase variant) 1052 1053 ```http 1054 POST /auth/session_code HTTP/1.1 1055 Host: cozy.example.org 1056 Accept: application/json 1057 Content-Type: application/json 1058 ``` 1059 1060 ```json 1061 { 1062 "passphrase": "hashed", 1063 "two_factor_token": "123123123123", 1064 "two_factor_passcode": "678678" 1065 } 1066 ``` 1067 1068 #### Response 1069 1070 ```http 1071 HTTP/1.1 201 Created 1072 Content-Type: application/json 1073 ``` 1074 1075 ```json 1076 { 1077 "session_code": "HzEFM3JREpIB6532fQc1FP2t4YJKt3gI" 1078 } 1079 ``` 1080 1081 The flagship will then be able to open a webview for 1082 `https://cozy-home.example.org/?session_code=HzEFM3JREpIB6532fQc1FP2t4YJKt3gI`. 1083 1084 #### Response (2FA needed) 1085 1086 In case of error where 2FA is needed, the response will be: 1087 1088 ```http 1089 HTTP/1.1 403 Forbidden 1090 Content-Type: application/json 1091 ``` 1092 1093 ```json 1094 { 1095 "error": "two factor needed", 1096 "two_factor_token": "123123123123" 1097 } 1098 ``` 1099 1100 ### FAQ 1101 1102 > What format is used for tokens? 1103 1104 The access tokens are formatted as [JSON Web Tokens (JWT)](https://jwt.io/), 1105 like this: 1106 1107 | Claim | Fullname | What it identifies | 1108 | ------- | --------- | ------------------------------------------------------------------ | 1109 | `aud` | Audience | Identify the recipient where the token can be used (like `access`) | 1110 | `iss` | Issuer | Identify the Cozy instance (its domain in fact) | 1111 | `iat` | Issued At | Identify when the token was issued (Unix timestamp) | 1112 | `sub` | Subject | Identify the client that can use the token | 1113 | `scope` | Scope | Identify the scope of actions that the client can accomplish | 1114 1115 The `scope` is used for [permissions](permissions.md). 1116 1117 Other tokens can be JWT with a similar formalism, or be a simple random value 1118 (when we want to have a clear revocation process). 1119 1120 > What happens when the user has lost her passphrase? 1121 1122 She can reset it from the command-line, like this: 1123 1124 ```sh 1125 $ cozy-stack instances reset-passphrase cozy.example.org 1126 ek0Jah1R 1127 ``` 1128 1129 A new password is generated and print in the console. 1130 1131 > Is two-factor authentication (2FA) possible? 1132 1133 Yes, it's possible. Via the cozy-settings application, the two-factor 1134 authentication can be activated. 1135 1136 Here is how it works in more details: 1137 1138 On each connection, when the 2FA is activated, the user is asked for its 1139 passphrase first. When entering correct passphrase, the user is then asked for: 1140 1141 - a TOTP (Timebased One-Time password, RFC 6238) derived from a secret 1142 associated with the instance. 1143 - a short term timestamped MAC with the same validity time-range and also 1144 derived from the same secret. 1145 1146 The TOTP is valid for a time range of about 5 minutes. When sending a correct 1147 and still-valid pair `(passcode, token)`, the user is granted with 1148 authentication cookie. 1149 1150 The passcode can be sent to the instance's owner via email — more transport 1151 shall be added later. 1152 1153 ### POST /auth/tokens/konnectors/:slug 1154 1155 This endpoint can be used by the flagship application in order to create a 1156 token for the konnector with the given slug. This token can then be used by the 1157 client-side konnector to make requests to cozy-stack. 1158 The flagship app will need to use its own access token to request the konnector 1159 token. 1160 1161 #### Request 1162 1163 ```http 1164 POST /auth/tokens/konnectors/impots HTTP/1.1 1165 Host: cozy.example.org 1166 Accept: application/json 1167 Authorization: Bearer eyJpc3Mi... 1168 ``` 1169 1170 #### Response 1171 1172 ```http 1173 HTTP/1.1 201 Created 1174 Content-Type: application/json 1175 ``` 1176 1177 ```json 1178 "OWY0MjNjMGEtOTNmNi0xMWVjLWIyZGItN2I5YjgwNmRjYzBiCg" 1179 ``` 1180 1181 ### POST /auth/share-by-link/password 1182 1183 This route is used when a share by link is protected by password. The password 1184 can be sent to this route to create a cookie that will allow to use the 1185 sharecode and access the shared page. 1186 1187 #### Request 1188 1189 ```http 1190 POST /auth/clients/share-by-link/password HTTP/1.1 1191 Host: cozy.example.org 1192 Content-Type: application/x-www-form-urlencoded 1193 1194 password=HelloWorld!&perm_id=123456789 1195 ``` 1196 1197 #### Response 1198 1199 ```http 1200 HTTP/1.1 200 OK 1201 Content-Type: application/json 1202 Set-Cookie: pass123... 1203 ``` 1204 1205 ```json 1206 { 1207 "password": "ok" 1208 } 1209 ``` 1210 1211 ### FAQ 1212 1213 > What format is used for tokens? 1214 1215 The access tokens are formatted as [JSON Web Tokens (JWT)](https://jwt.io/), 1216 like this: 1217 1218 | Claim | Fullname | What it identifies | 1219 | ------- | --------- | ----------------------------------------------------------------------- | 1220 | `aud` | Audience | Identify the recipient where the token can be used (i.e. `konn`) | 1221 | `iss` | Issuer | Identify the Cozy instance (its domain in fact) | 1222 | `iat` | Issued At | Identify when the token was issued (Unix timestamp) | 1223 | `sub` | Subject | Identify the client that can use the token (i.e. the konnector slug) | 1224 | `scope` | Scope | Konnector tokens don't have any scope | 1225 1226 1227 ## Client-side apps 1228 1229 **Important**: OAuth2 is not used here! The steps looks similar (like obtaining 1230 a token), but when going in the details, it doesn't match. 1231 1232 ### How to register the application? 1233 1234 The application is registered at install. See [app management](apps.md) for 1235 details. 1236 1237 ### How to get a token? 1238 1239 When a user access an application, she first loads the HTML page. Inside this 1240 page, a token specific to this app is injected (only for private routes), via a 1241 templating method. 1242 1243 We have prefered our custom solution to the implicit grant type of OAuth2 for 2 1244 reasons: 1245 1246 1. It has a better User Experience. The implicit grant type works with 2 1247 redirections (the application to the stack, and then the stack to the 1248 application), and the first one needs JS to detect if the token is present or 1249 not in the fragment hash. It has a strong impact on the time to load the 1250 application. 1251 1252 2. The implicit grant type of OAuth2 has a severe drawback on security: the 1253 token appears in the URL and is shown by the browser. It can also be leaked 1254 with the HTTP `Referer` header. 1255 1256 The token will be given only for the authenticated user. For nested subdomains 1257 (like `calendar.joe.example.net`), the session cookie from the stack is enough 1258 (it is for `.joe.example.net`). 1259 1260 But for flat subdomains (like `joe-calendar.example.net`), it's more 1261 complicated. On the first try of the user, she will be redirected to the stack. 1262 As she is already logged-in, she will be redirected to the app with a session 1263 code (else she can login). This session code can be exchanged to a session 1264 cookie. A redirection will still happen to remove the code from the URL (it 1265 helps to avoid the code being saved in the browser history). For security 1266 reasons, the session code have the following properties: 1267 1268 - It can only be used once. 1269 - It is tied to an application (`calendar` in our example). 1270 - It has a very short time span of validity (1 minute). 1271 1272 ### How to use a token? 1273 1274 The token can be sent to the cozy-stack as a `Bearer` token in the 1275 `Authorization` header, like this: 1276 1277 ```http 1278 GET /data/io.cozy.events/6494e0ac-dfcb-11e5-88c1-472e84a9cbee HTTP/1.1 1279 Host: cozy.example.org 1280 Authorization: Bearer application-token 1281 ``` 1282 1283 If the user is authenticated, her cookies will be sent automatically. The 1284 cookies are needed for a token to be valid. 1285 1286 ### How to refresh a token? 1287 1288 The token is valid only for 24 hours. If the application is opened for more than 1289 that, it will need to get a new token. But most applications won't be kept open 1290 for so long and it's okay if they don't try to refresh tokens. At worst, the 1291 user just had to reload its page and it will work again. 1292 1293 The app can know it's time to get a new token when the stack starts sending 401 1294 Unauthorized responses. In that case, it can fetches the same html page that it 1295 was loaded initially, parses it and extracts the new token. 1296 1297 ## Third-party websites 1298 1299 ### How to register the application? 1300 1301 If a third-party websites would like to access a cozy, it had to register first. 1302 For example, a big company can have data about a user and may want to offer her 1303 a way to get her data back in her cozy. When the user is connected on the 1304 website of this company, she can give her cozy address. The website will then 1305 register on this cozy, using the OAuth2 Dynamic Client Registration Protocol, as 1306 explained [above](#post-authregister). 1307 1308 ### How to get a token? 1309 1310 To get an access token, it's enough to follow the authorization code flow of 1311 OAuth2: 1312 1313 - sending the user to the cozy, on the authorize page 1314 - if the user approves, she is then redirected back to the client 1315 - the client gets the access code and can exchange it to an access token. 1316 1317 ### How to use a token? 1318 1319 The access token can be sent as a bearer token, in the Authorization header of 1320 HTTP: 1321 1322 ```http 1323 GET /data/io.cozy.contacts/6494e0ac-dfcb-11e5-88c1-472e84a9cbee HTTP/1.1 1324 Host: cozy.example.org 1325 Accept: application/json 1326 Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ 1327 ``` 1328 1329 ### How to refresh a token? 1330 1331 The access token will be valid only for 24 hours. After that, a new access token 1332 must be asked. To do that, just follow the refresh token flow, as explained 1333 [above](#post-authaccess_token). 1334 1335 ## Devices and browser extensions 1336 1337 For devices and browser extensions, it is nearly the same than for third-party 1338 websites. The main difficulty is the redirect_uri. In OAuth2, the access code is 1339 given to the client by redirecting the user to an URL controlled by the client. 1340 But devices and browser extensions don't have an obvious URL for that. 1341 1342 The IETF has published an RFC called 1343 [OAuth 2.0 for Native Apps](https://tools.ietf.org/html/draft-ietf-oauth-native-apps-05). 1344 1345 ### Native apps on desktop 1346 1347 A desktop native application can start an embedded webserver on localhost. The 1348 redirect_uri will be something like `http://127.0.0.1:19856/callback`. 1349 1350 ### Native apps on mobile 1351 1352 On mobile, the native apps can often register a custom URI scheme, like 1353 `com.example.oauthclient:/`. Just be sure that no other app has registered 1354 itself with the same URI. 1355 1356 ### Chrome extensions 1357 1358 Chrome extensions can use URL like 1359 `https://<extension-id>.chromiumapp.org/<anything-here>` for their usage. See 1360 https://developer.chrome.com/apps/app_identity#non for more details. It has also 1361 a method to simplify the creation of such an URL: 1362 [`chrome.identity.getRedirectURL`](https://developer.chrome.com/apps/identity#method-getRedirectURL). 1363 1364 ### Firefox extensions 1365 1366 It is possible to use an _out of band_ URN: `urn:ietf:wg:oauth:2.0:oob:auto`. 1367 The token is then extracted from the title of the page. See 1368 [this addon for google oauth2](https://github.com/AdrianArroyoCalle/firefox-addons/blob/master/addon-google-oauth2/addon-google-oauth2.js) 1369 as an example. 1370 1371 ## Security considerations 1372 1373 The master password, the password known by the user, is derived on the clients 1374 to give two keys. The first key is used to login on the stack, the second key 1375 is used to do client-side encryption. The derivation for the login password is 1376 currently done with the PBKDF2 algorithm (with SHA256), but we have anticipated 1377 the possibility of changing to another algorithm if desirable. 1378 1379 The derived password is stored on the server in a secure fashion, with a 1380 password hashing function. The hashing function and its parameter are stored 1381 with the hash, in order to make it possible to change the algorithm and/or the 1382 parameters later if we had any suspicion that it became too weak. The initial 1383 algorithm is [scrypt](https://pkg.go.dev/golang.org/x/crypto/scrypt). 1384 1385 The access code is valid only once, and will expire after 5 minutes 1386 1387 Dynamically registered applications won't have access to all possible scopes. 1388 For example, an application that has been dynamically registered can't ask the 1389 cozy owner to give it the right to install other applications. This limitation 1390 should improve security, as avoiding too powerful scopes to be used with unknown 1391 applications. 1392 1393 The cozy stack will apply rate limiting to avoid brute-force attacks. 1394 1395 The cozy stack offers 1396 [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS) 1397 for most of its services. But it's disabled for `/auth` (it doesn't make sense 1398 here) and for the client-side applications (to avoid leaking their tokens). 1399 1400 The client should really use HTTPS for its `redirect_uri` parameter, but it's 1401 allowed to use HTTP for localhost, as in the native desktop app example. 1402 1403 OAuth2 says that the `state` parameter is optional in the authorization code 1404 flow. But it is mandatory to use it with Cozy. 1405 1406 For more on this subject, here is a list of links: 1407 1408 - https://www.owasp.org/index.php/Authentication_Cheat_Sheet 1409 - https://tools.ietf.org/html/rfc6749#page-53 1410 - https://tools.ietf.org/html/rfc6819 1411 - https://tools.ietf.org/html/draft-ietf-oauth-closing-redirectors-00 1412 - http://www.oauthsecurity.com/ 1413 1414 ## Conclusion 1415 1416 Security is hard. If you want to share some concerns with us, do not hesitate to 1417 send us an email to security AT cozycloud.cc.