Skip to content
Snippets Groups Projects
description.md 6.48 KiB
Newer Older
Hugo NOUTS's avatar
Hugo NOUTS committed
This section of documentation refers to the Oauth protocols working hand in hand with our custom proxy and the cozy-stack.
Hugo's avatar
Hugo committed
To fully understand its whereabouts, you should also look at the [enedis konnector](../ecolyo/konnectors/enedis.md) and [grdf konnector](../ecolyo/konnectors/grdf.md) documentation.
Hugo NOUTS's avatar
Hugo NOUTS committed

!!! info "proxy code source"
    Feel free to check the proxy [code](https://forge.grandlyon.com/pocs/cozy/cozy-oauth-proxy) at all time when reading this documentation.

## Oauth Dance

To access customer data, one must first obtain customer authorization. This authorization is materialized by an access token and it must be obtained by the APIs exposed by each energy providers.
Hugo NOUTS's avatar
Hugo NOUTS committed
These APIs implement Oauth 2.0 protocol, it requires authentication from the customer along with its given consent.
See both **[Enedis](./use_cases/enedis.md)** and **[Grdf](./use_cases/grdfadict.md)** use cases before going further.
Hugo NOUTS's avatar
Hugo NOUTS committed
### Cozy Oauth Protocol

!!! info "cozy oauth flow documentation" 
    [https://docs.cozy.io/en/cozy-stack/konnectors-workflow/#reminder-oauth-flow](https://docs.cozy.io/en/cozy-stack/konnectors-workflow/#reminder-oauth-flow)

#### Couchdb

Hugo NOUTS's avatar
Hugo NOUTS committed
The couchdb database must hold all informations needed for the konnector authentication to work properly.

Auth informations are stored in the **secrets/io-cozy-account_types** database.
Hugo NOUTS's avatar
Hugo NOUTS committed
You can create manually the document by entering these parameters for each konnector:

<table>
  <colgroup>
    <col width="30%">
    <col width="70%">
  </colgroup>
  <thead>
    <tr class="header">
      <th>Name</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>_id</td>
      <td>Name of your konnector, for instance: enedisgrandlyon</td>
    </tr>
    <tr>
      <td>grant_mode</td>
      <td>authorization_code</td>
    </tr>
    <tr>
      <td>client_id</td>
      <td>Application id given by the API provider</td>
    </tr>
    <tr>
      <td>client_secret</td>
      <td>Secret also given by the API provider</td>
    </tr>
    <tr>
      <td>auth_endpoint</td>
      <td>Authorize endpoint to request when starting the oauth protocol</td>
    </tr>
    <tr>
      <td>token_endpoint</td>
      <td>Token endpoint to request, will be called when the auth endpoint response reaches the stack</td>
    </tr>
    <tr>
      <td>token_mode</td>
      <td>get</td>
    </tr>
  </tbody>
</table>

Once the document is created, when launching the konnector from the cozy-home or inside the running application. The oauth flow will start.

The cozy-stack will request the authorize endpoint, then call the token endpoint with the code received from the auth step.

If the token request is a success. An account/service-name database will be added in couchdb containing all informations needed for authentication and the konnector will be free to work on all endpoints within its scope.

Hugo NOUTS's avatar
Hugo NOUTS committed
### Why we Need a Proxy
The Oauth dance could be easily wrapped up with the two requests seen above. But since all cozy applications are hosted on different personnal clouds, following this guideline would mean that we need a **client_id** and a **client_secret** for each one of all the applications running.
To answer this issue, two solutions are possible depending on what the energy supplier is willing to do.
- Providers could allow wildcard subdomains when registering the callback URI, it would parse the subdomain and adapt its redirection when answering **/auth** call.

Exemple:

    https//*.cozygrandlyon.cloud/account/redirect -> parse subdomain before .cozy

    xyz.cozygrandlyon.cloud/account/redirect -> redirect to xyz
    toto.cozygrandlyon.cloud/account/redirect -> redirect to toto

- If the provider (Enedis for instance) is not accepting wildcards, then we put a proxy as a middleware to provide a generic endpoint to cater for all Oauth2 redirections. 
Hugo NOUTS's avatar
Hugo NOUTS committed
#### Result

Hugo NOUTS's avatar
Hugo NOUTS committed
With that in mind, the proxy is now the one calling the auth and token provider endpoints. The instance name will be contained in redirect_uri, the stack will insert this parameters by itself in the /auth call.
Hugo NOUTS's avatar
Hugo NOUTS committed
3 endpoints are created in the proxy for **each energy supplier**:
Hugo NOUTS's avatar
Hugo NOUTS committed

Hugo NOUTS's avatar
Hugo NOUTS committed
- One for the auth
- One for the token
Hugo NOUTS's avatar
Hugo NOUTS committed
- One for the redirect uri
Hugo NOUTS's avatar
Hugo NOUTS committed
#### Proxy flow

```plantuml
  Stack -> Proxy: calls
  Proxy -> Provider: calls
  Proxy <-- Provider: responds with oauth code on proxy/redirect
  Stack <-- Proxy: redirect to user instance
  Stack -> Proxy: calls
  Proxy -> Provider: calls for token or refresh
  Proxy <-- Provider: responds
  Stack <-- Proxy: token
```
Hugo NOUTS's avatar
Hugo NOUTS committed
## Proxy Code Explained

Hugo NOUTS's avatar
Hugo NOUTS committed
!!! info "reminder"
    Feel free to check the proxy [code](https://forge.grandlyon.com/pocs/cozy/cozy-oauth-proxy) at all time when reading this documentation.

The proxy is coded in golang.

Hugo NOUTS's avatar
Hugo NOUTS committed
It is composed of six endpoints as seen above. The first endpoint to be called is **/auth**.
Hugo NOUTS's avatar
Hugo NOUTS committed

#### auth

Hugo NOUTS's avatar
Hugo NOUTS committed
Originally called from a cozy-stack trying to setup its konnector. The proxy gets these informations from the query:
Hugo NOUTS's avatar
Hugo NOUTS committed

Hugo NOUTS's avatar
Hugo NOUTS committed
- client_id
- duration
- redirect_uri (auto inserted by the cozy-stack, except if you specify **skip_redirect_uri:true** in the couchdb)
- response_type
Hugo NOUTS's avatar
Hugo NOUTS committed
- state (as it was conceived by the cozy-stack)
Hugo NOUTS's avatar
Hugo NOUTS committed

![auth_params](enedis-auth-params.png)

The state will be merged with the instance name, then decomposed again when reaching /redirect. This way the proxy is able to keep track of the cozy instance originally calling.
Hugo NOUTS's avatar
Hugo NOUTS committed

With all these informations, the proxy can contact the provider **/auth** endpoint to start the oauth dance.

##### Enedis
Hugo NOUTS's avatar
Hugo NOUTS committed

!!! warning "note"
    See that a new composed state is sent to enedis, it is made of the former state conceived by the cozy-stack + the cozyOrigin instance name. This will be usefull when enedis is leading the oauth dance to the next step and we will need the name of the cozy to answer.

Once the call is sent, enedis will point to the **/redirect** endpoint.

##### Grdf

> To be redacted

Hugo NOUTS's avatar
Hugo NOUTS committed
#### redirect

Retrieve the *code*, *usage_point_id*, and *state* answered by Enedis.
Hugo NOUTS's avatar
Hugo NOUTS committed

Split the customed state that was modified in the **/auth** process. From this split it creates two variables :

- state
- host

Finally redirect all these parameters in a query to the cozy-stack (the cozy-stack which is still waiting for an answer from its /auth call).

Hugo NOUTS's avatar
Hugo NOUTS committed
!!! warning "state / instance"
    The state must be recovered without the instance name, otherwise the cozy-stack won't recognized it and the handshake will fail.

Hugo NOUTS's avatar
Hugo NOUTS committed
#### token

Gathering from query or parameters all params.

Sends a post request to the provider /token endpoint. 
Hugo NOUTS's avatar
Hugo NOUTS committed
The stack will store the response params in a *accounts* couchdb database.