# 👮‍♀️ Authentication

## Authentication

To ensure security and confidentiality of our services, it is required to verify the user's identity for each request.

These pieces of information are stored in an access **token**. This token is delivered by our authentication service.

Below are detailed the **API endpoints** used for this service.

| **method** | **url**                        | **params**        | **description**                                                                      |
| ---------- | ------------------------------ | ----------------- | ------------------------------------------------------------------------------------ |
| GET        | <https://kligo.medeo.io/auth/> | email             | returns a challenge in exchange of the user's email address.                         |
| POST       | <https://kligo.medeo.io/auth/> | challenge, userId | returns the access token if the user id and the corresponding challenge are correct. |

## **How to obtain a token**

In order to obtain a **token**, the client must be authenticate by the service. This authentication is performed using a **challenge** (i.e. a unique string forged using the information contained in our database):

1. First the client requests a **challenge f**rom the server.
2. Using the user credentials (i.e. the password) the client tries to solve the **challenge.**
3. The client posts its response to the server.
4. The server effectively solves the **challenge** with the credentials stored in its database and compares the two responses.
5. If the responses match, the server returns a **token**.

> This approach ensures a certain level of security because the **password** is not sent during the authentication process.

Each of the authentication steps is defined in the sections below.

## **Requesting the challenge**

### **Description**

In order to obtain a token, the client is responsible for requesting a challenge. This challenge can be requested using the following **API endpoint**:

`[GET] https://kligo.medeo.io/auth?email=<your@mail.com>`

This endpoint expects an email address to be passed.

### **Response**

Depending on the email provided, different responses can be expected:

| **status**           | **body**          | **description**                                                                          |
| -------------------- | ----------------- | ---------------------------------------------------------------------------------------- |
| 200 - OK             | userId, challenge | This response is composed of the challenge to solve and the id associated with the user. |
| 404 - Not Found      | message           | The email provided is not associated with a known user.                                  |
| 500 - Internal Error | message           | Something went wrong on our end.                                                         |

Here are some example response:

```
//  For a 200 - OK response, the body should look like:

    {
        "userId": "<yourUserId>",
        "challenge":"<yourChallenge>"
    }
```

```
//  For a 200 - OK response, the body should look like:

    {
        "userId": "<yourUserId>",
        "challenge":"<yourChallenge>"
    }
```

**Here is a comprehensive example for requesting a challenge:**

{% tabs %}
{% tab title="JavaScript" %}

```javascript
fetch(`https://kligo.medeo.io/api/auth?email=${email}`, {
    method: 'GET',
    headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json; charset=utf-8'
    }
}).then(response => {
    /* ... */
});
```

{% endtab %}

{% tab title="Swift" %}

```swift
 func getChallenge(email: String) {
    let session = URLSession.shared
    let url = URL(string: "kligo.medeo.io/api/auth?email=\(email)")
    var request = URLRequest(url: url!)
    session.dataTask(with: request) {(data, response, error) in
        if let data = data {
            do {
                let json = try JSONSerialization.jsonObject(with: data, options: [])
                if var dict = json as? Dictionary<String, String> {
                    // you get your challenge here    
                }
            } catch {
                print(error)
            }
        }
    }.resume()
}
```

{% endtab %}

{% tab title="C#" %}

```javascript
ServicePointManager.SecurityProtocol =
SecurityProtocolType.Tls12 |
SecurityProtocolType.Tls11 |
SecurityProtocolType.Tls;

var client = new RestClient("https://kligo.medeo.io/api");
var request = new RestRequest("auth?email={email}", Method.GET);
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Accept", "application/json");

request.AddParameter("email", email, ParameterType.UrlSegment);
request.RequestFormat = DataFormat.Json;

client.ExecuteAsync(request, response => {
JsonDeserializer deserial = new JsonDeserializer();
var result = response.Content;
var deserializedResult = deserial.Deserialize<User>(responseChallenge);
user.Challenge = deserializedResult.Challenge;
user.UserId = deserializedResult.UserId;
/* ... */
});
```

{% endtab %}
{% endtabs %}

## **Solving the challenge**

### **description**

**Once fetched, the challenge must be solved using the user credentials. The expected solution is computed as follows:**

* First, concatenate the challenge string with the user password.
* Then hash the concatenated string using a **SHA256** hashing method.
* Send back the hashed string along with the userId

### **response**

**The authentication service will responds depending on the solution passed. There are three cases:**

* The `userId` is incorrect
* The `solution` is incorrect
* Everything is correct

| **status**           | **body** | **description**                  |
| -------------------- | -------- | -------------------------------- |
| 200 - OK             | token    | The authorization token          |
| 404 - Not Found      | message  | The userId provided is not known |
| 400 - Bad Request    | message  | Incorrect password               |
| 500 - Internal Error | message  | Something went wrong on our end  |

Once you receive the token, its TTL attribute is set to **1 day**. Passed this date, the token will no longer authenticate your requests and our services will automatically respond with a401 UnauthorizedHTTP response.

In other words, it will be required to start again an authentication process to continue to use our services.

**Here are some example responses:**

```
//  For a 200 - OK response, the body should look like:

{
    "token": "aaa.bbb.ccc"
}
```

```
//    For a 400 - Bad Request response:   

{
  "message": "Bad Request"
}
```

```
//    For a 404 - Not Found response:   

{
    "message": "Not Found"
}
```

**Here is the first method required for getting the token:**

{% tabs %}
{% tab title="JavaScript" %}

```javascript
// performs a simple concatenation of the challenge and the password
let concatenatedString = [challenge, password].join('');
//simply hash the result
let solution = SHA256(concatenatedString);
```

{% endtab %}

{% tab title="Swift" %}

```swift
// Using CryptoSwift pod

let hashedChallenge = "\(challenge)\(password)".sha256()

```

{% endtab %}

{% tab title="C#" %}

```csharp
public static String sha256_hash(String value)
{
    using (SHA256 hash = SHA256Managed.Create())
    {
        return String.Concat(hash
          .ComputeHash(Encoding.UTF8.GetBytes(value))
          .Select(item => item.ToString("x2")));
    }
}
```

{% endtab %}
{% endtabs %}

**Eventually, here is an example of posting the solution to the authentication service :**

{% tabs %}
{% tab title="JavaScript" %}

```javascript
fetch('https://kligo.medeo.io/api/auth', {
    method: 'POST',
    body: JSON.stringify({userId: userId, challenge: solution}),
    headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json; charset=utf-8'
    } ,
    credentials: 'same-origin',
});
```

{% endtab %}

{% tab title="Swift" %}

```swift
func postChallenge(userId: String, hashedChallenge: String, password: String) {
    var request = URLRequest(url: "https://kligo.medeo.io/api/auth")
    let body: [String: Any] = ["userId": userId, "challenge": hashedChallenge]
    request.httpMethod = "POST"
    guard let httpBody = try? JSONSerialization.data(withJSONObject: body, options: []) else { return }
    request.httpBody = httpBody
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    session.dataTask(with: request) {(data, response, error) in
        if let data = data {
            do {
                let json = try JSONSerialization.jsonObject(with: data, options: [])
                if let dict = json  as? Dictionary<String, String> {
                    // get the tokens here
                }
            } catch {
                print(error)
            }
        }
    }.resume()
}
```

{% endtab %}

{% tab title="C#" %}

```csharp
var requestToken = new RestRequest("auth", Method.POST);

requestToken.AddHeader("Content-Type", "application/json");
requestToken.AddHeader("Accept", "application/json");
requestToken.AddParameter("userId", userId);
requestToken.AddParameter("challenge", sha256_hash(challenge+password));

requestToken.RequestFormat = DataFormat.Json;

client.ExecuteAsync(requestToken, responseToken => {
    var resultToken = responseToken.Content;
    var deserializedResultToken = deserial.Deserialize<User>(responseToken);
    user.Token = deserializedResultToken.Token;
});
```

{% endtab %}
{% endtabs %}
