Skip to content
Snippets Groups Projects
description.md 6.55 KiB
Newer Older
Bastien DUMONT's avatar
Bastien DUMONT committed
# Description

This section of documentation refers to the Oauth protocols working hand in hand with our custom proxy and the cozy-stack.
Bastien DUMONT's avatar
Bastien DUMONT committed
To fully understand its whereabouts, you should also look at the [enedis konnector](/konnectors/enedis/) and [grdf konnector](/konnectors/grdf/) documentation.
![gitlab](../img/gitlab-logo.svg) [proxy](https://forge.grandlyon.com/pocs/cozy/cozy-oauth-proxy)

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

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.
Bastien DUMONT's avatar
Bastien DUMONT committed

### Cozy Oauth Protocol

Bastien DUMONT's avatar
Bastien DUMONT committed
!!! 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
The CouchDB database must hold all information needed for the konnector authentication to work properly.
Hugo NOUTS's avatar
Hugo NOUTS committed
Auth information are stored in the **secrets/io-cozy-account_types** database.
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 information needed for authentication and the konnector will be free to work on all endpoints within its scope.
Hugo NOUTS's avatar
Hugo NOUTS committed
The Oauth dance could be easily wrapped up with the two requests seen above. But since all cozy applications are hosted on different personal 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.

Hugo NOUTS's avatar
Hugo NOUTS committed
Example:

    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

Bastien DUMONT's avatar
Bastien DUMONT committed
- 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 redirection.

#### Result

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.

3 endpoints are created in the proxy for **each energy supplier**:

- One for the auth
- One for the token
- One for the redirect uri

#### 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
```

## Proxy Code Explained

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

It is composed of six endpoints as seen above. The first endpoint to be called is **/auth**.

Bastien DUMONT's avatar
Bastien DUMONT committed
### auth
Hugo NOUTS's avatar
Hugo NOUTS committed
Originally called from a cozy-stack trying to setup its konnector. The proxy gets these information from the query:
- redirect_uri (auto inserted by the cozy-stack, except if you specify **skip_redirect_uri:true** in the CouchDB)
- response_type
- state (as it was conceived by the cozy-stack)

![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 information, the proxy can contact the provider **/auth** endpoint to start the oauth dance.
Bastien DUMONT's avatar
Bastien DUMONT committed
#### Enedis
Hugo NOUTS's avatar
Hugo NOUTS committed
    See that a new composed state is sent to enedis, it is made of the former state conceived by the cozy-stack + the original instance name. This will be useful 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.

Bastien DUMONT's avatar
Bastien DUMONT committed
#### Grdf
Bastien DUMONT's avatar
Bastien DUMONT committed
### redirect

Retrieve the *code*, *usage_point_id*, and *state* answered by Enedis.

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

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

Bastien DUMONT's avatar
Bastien DUMONT committed
### token

Gathering from query or parameters all params.

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