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&quota=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.