# Auth

This guide walks you through authenticating with our API. Every request must be
correctly authenticated with a token, must be safe to resend if a package is
dropped, and must be protected against modification and token capture via
signatures. Additionally, all requests must use *https* as the API does not
accept plaintext requests over *http*.

These 3 HTTP headers secure every request to the API:

1. An **Authorization** HTTP header containing the value `Bearer <access_token>`
where the `<access_token>` is acquired through the
[Login endpoint](/products/partner-api/reference/security/login_api_v1_login__post).
2. An **x-jiko-idempotency** HTTP header set to a random uuid for this action,
in order to signify a unique request to the API from the Partner's
perspective. This allows you to send the same request multiple times if the
first response gets lost in transit.
3. An **x-jiko-signature** HTTP header set to a base64 encoded HMAC-SHA256 hash
of x-jiko-idempotency+request pathname+body using the *shared secret* as a
key. This shared secret is never sent along with the requests, so even if a
token is captured, any malicious requests will be dropped on signature
mismatch.


## Authorization Header

If you haven't already, reach out to your Jiko point of contact to receive a
*username*, *password*, and *shared signing secret*. Your company will also be
assigned a API URL *prefix*.

To fetch a token, start by setting your *username*, *password*, and *signing
secret* (used later) as environment variables using the following snippet:


```bash
export JIKO_USER='your-username';
export JIKO_PASS='your-password';
export JIKO_SIGNING_SECRET='your-signing-secret';
export PREFIX='your-prefix';
```

Then, send a POST request to
[Login](/products/partner-api/reference/security/login_api_v1_login__post)
with the username and password as parameters in the request:


```bash
curl -s "https://{PREFIX}.sandbox-api.jikoservices.com/api/v1/login/" \
-H 'Content-type: application/json' \
-d '{
 "username": "'$JIKO_USER'",
 "password": "'$JIKO_PASS'"
}'
```

Your response should look like this:


```json
{
  "token": "your-token",
  "expires": "2012-12-12T12:12:12.946661+00:00"
}
```

This token will be used in the rest of the tutorial, so save it to your
environment:


```bash
export TOKEN="your-token"
```

To do the same through Python, install the requests module with
`pip install requests` and then run this snippet:


```python
import os
import requests

prefix = os.environ["PREFIX"]
root = "https://$PREFIX.sandbox-api.jikoservices.com"
endpoint = "/api/v1/login/"
url = root + endpoint # The endpoint variable is used later when signing the request
body = {"username": os.environ["JIKO_USER"], "password": os.environ["JIKO_PASS"]}
request = requests.post(url, json=body)
response = request.json()

print(response)
token = response["token"]
```

This token is valid for 1 hour, and the expiration time is also provided in the
response. Now that you've acquired a token, it can be used to construct the
**Authorization** header like so: `Authorization: Bearer <access_token>`

## Idempotency

A uuid for the idempotency header is easy to come by. In a terminal, run:


```bash
uuidgen
```

to generate a unique uuid for the header. The output should look like this:


```bash
0FA3047F-7364-47AF-A679-D391018B79C4
```

This program is pre-installed on MacOS and most Linux systems, but if it's
missing on your system, install it with `sudo apt-get install uuid-runtime`

In Python, you can run this snippet:


```python
import uuid

x_jiko_idempotency = str(uuid.uuid4())

print(x_jiko_idempotency)
```

Now that you've acquired a uuid, it can be used to construct the
**x-jiko-idempotency** header like so: `x-jiko-idempotency: <uuid>`

## Request Signing (Signature)

Now that you've got an authorized and idempotent request ready to send, the
final step is to sign the request using the *shared signing secret*. To sign a
request, we're going to need a HTTP *body* and a simple hello-world endpoint to
send our first request. In this case, we'll be fetching the
[Pocket data](/products/partner-api/reference/pockets/list-pockets-v2)
for a dummy customer that is automatically created in the sandbox environment
for all partners.

For the terminal, we need to create a few functions to help us:


```bash
get_idempotency() { \
  local idempotency = $(uuidgen);
  # On MacOS, uuidgen is uppercase.
  # This line makes it lowercase.
  local idempotency = "$(tr "[A-Z]" "[a-z]" <<< "$idempotency")";
  echo $idempotency;
}

get_signature() { \
  local endpoint = $1;
  local body = $2;
  local idempotency = $3;

  local hash_string = "$idempotency$endpoint$body";
  local signature = $(echo -n $hash_string | openssl sha256 -binary -hmac $JIKO_SIGNING_SECRET | base64);
  echo $signature
}

send_jiko_request() { \
  local method = $1;
  local endpoint = $2;
  local body = ${3:-"{}"};
  idempotency = $(get_idempotency);
  curl --request $method \
  --url https://$PREFIX.sandbox-api.jikoservices.com$endpoint \
  --header "Authorization: Bearer $TOKEN" \
  --header 'Content-Type: application/json' \
  --header "x-jiko-idempotency: $idempotency" \
  --header "x-jiko-signature: $(get_signature $endpoint $body $idempotency)" \
  --data $body \
  | jq
}
```

Now, we can finally send our first real request:


```bash
send_jiko_request GET "/api/v1/agreements/"
```

To do the same thing in Python, create similar functions and run them with the
following code:


```python
import base64
import hashlib
import hmac
import json

def get_idempotency():
  idempotency = str(uuid.uuid4())
  return idempotency

def get_signature(idempotency: str, endpoint: str, body: str):
  hash_string = idempotency + endpoint + body
  hash_input = bytes(hash_string, "utf-8")
  signing_secret = bytes(os.environ["JIKO_SIGNING_SECRET"], "utf-8")
  hashed_signature = hmac.new(
      key=signing_secret, msg=hash_input, digestmod=hashlib.sha256
  ).digest()
  signature = base64.b64encode(hashed_signature)
  return signature

customer_id = "c26ed6d6-cdd0-41a3-ab54-84597309ae3a"
endpoint = "/api/v1/customers/" + customer_id + "/jiko-accounts/"
url = root + endpoint
body = {}
# Omitting the body gives the same result, but this code example
# is general and works both with and without a body

headers = {}
headers["Authorization"] = "Bearer " + token
headers["x-jiko-idempotency"] = get_idempotency()
headers["x-jiko-signature"] = get_signature(
  headers["x-jiko-idempotency"], endpoint, json.dumps(body)
)

resp = requests.get(url, json=body, headers=headers)

print(resp.text)
```

Congratulations! You've taken the first step to offering Jiko money storage and
movement to your customers.

### Postman request signing

When using [Postman](https://getpostman.com) to test requests against the
sandbox Partner API, request signatures can be automated using a pre-request
script. The following script dynamically generates the required headers for
request signing. To use this script, ensure that the `secret` environment
variable is set to the shared secret provided by the Jiko team.


```js
// fetch the shared secret from the currently active Postman environment
const secret = pm.environment.get('secret')

const enc = new TextEncoder('utf-8')

let idempotencyKey = crypto.randomUUID()
let signature = await createSignature(idempotencyKey)

let headers = [
  ['x-jiko-idempotency', idempotencyKey],
  ['x-jiko-signature', signature],
]

headers.forEach(([key, value]) => pm.request.addHeader({ key, value }))

/**
 * Utility functions below
 */

async function createSignature(idempotency) {
  let path = pm.variables.replaceIn(pm.request.url).getPath()
  let body = pm.variables.replaceIn(pm.request.body).toString()

  if (pm.request.body.mode === 'raw') {
    pm.request.body.raw = body
  }

  let hmacKey = await createHmac(secret)
  return await digestMessage(hmacKey, idempotency + path + body)
}

async function createHmac(secret) {
  return await crypto.subtle.importKey(
    'raw',
    enc.encode(secret),
    {
      name: 'HMAC',
      hash: { name: 'SHA-256' },
    },
    false,
    ['sign', 'verify']
  )
}

async function digestMessage(key, message) {
  const hashBuffer = await crypto.subtle.sign('HMAC', key, enc.encode(message))
  const hashArray = new Uint8Array(hashBuffer)

  return btoa(String.fromCharCode.apply(null, hashArray))
}
```