Autenticação e segurança
Os endpoints destinados a parceiros têm as requisições validadas através do uso de um token de segurança. A montagem deste token acontece no lado do cliente.
O token deve ser utilizado em toda requisição, dado que ele leva em consideração a rota, o horário atual e o payload da requisição.
Obtendo suas credenciais
Para montar o token, obtenha suas credenciais com o time da Árvore. As credenciais para realizar a autenticação na API são compostas de uma access_key e uma access_key_id.
Geração do token
O token é uma junção de cinco valores, separados por vírgula, codificados via HMAC com o algoritmo SHA1, e posteriormente codificado via Base64.
Os valores que compõem o token são:
- Verbo HTTP utilizado na requisição. Ex:
POST. - Tipo de conteúdo utilizado na requisição. Ex:
application/json. - Hash do corpo da requisição, codificado via Base64. Ex:
7JnmJ3nblefY67zpbKm9rg==. - Rota da requisição. Ex:
/api/v2/partners/readers. - Horário atual, no formato
strftimecom os códigos"%a, %d %b %Y %H:%M:%S GMT". Ex:Wed, 16 Sep 2024 14:14:58 GMT.
Obtendo o hash do corpo da requisição
Caso a requisição não tenha um corpo, o content será uma string vazia. Se não, o content será o hash do corpo da requisição, codificado via Base64:
- Obtenha o JSON que será o body da requisição. Ex:
{"key": "value"}. - Em seguida, transforme o body utilizando o algoritmo MD5. Ex:
850d491f70778cfa331cede127b37013. - Por fim, codifique o hash obtido no passo anterior via Base64. Ex:
7JnmJ3nblefY67zpbKm9rg==.
Montagem do token
- Junte os valores acima na ordem em que foram declarados por vírgula. Ex:
{http_verb},{content_type},{body_hash},{request_uri},{current_time}. O valor resultante dessa junção será daqui em diante chamado decanonical_string. - Codifique a
canonical_stringvia HMAC com o algoritmo SHA1 usando aaccess_keycomo chave. - Codifique o valor acima via Base64.
- O valor resultante será daqui em diante chamado de
signature. - Por fim, use a
signaturee oaccess_key_idpara montar um token da seguinte forma:"APIAuth {access_key_id}:{signature}". - O valor gerado nesses passos deve aparecer nos headers da requisição sob a chave
Authorization. Ex:Authorization: APIAuth {access_key_id}:{signature}.
Realizando uma requisição
Por fim, a requisição deve ser feita para o endpoint desejado utilizando o header acima calculado, como por exemplo no comando curl abaixo:
curl -i -X POST \
-H 'Content-Type: application/json' \
-H 'Content-MD5: 7JnmJ3nblefY67zpbKm9rg==' \
-H 'DATE: Wed, 16 Sep 2024 14:14:58 GMT' \
-H 'Authorization: APIAuth <signature>' \
-d '{}' https://livros.arvore.com.br/api/v2/partners/readers
Repositório com exemplos
Para auxiliar com a autenticação e uso da API, a Árvore mantém um repositório com exemplos em diferentes linguagens. Acesse através do seguinte link:
Exemplo de geração do API Auth em Elixir
Abaixo, um exemplo de como gerar o token de autenticação utilizando Elixir:
access_key = "some_access_key"
access_key_id = "some_access_key_id"
# 1. HTTP Verb
http_verb = "POST"
# 2. Content Type
content_type = "application/json"
# 3. Body Hash
body = "{\"some_key\":\"some value\"}"
md5_content = :crypto.hash(:md5, body)
content = Base.encode64(md5_content) # 7JnmJ3nblefY67zpbKm9rg==
# 4. Request URI
path = "/api/v2/partners/readers"
# 5. Current Time
date = Timex.format!(DateTime.utc_now(), "%a, %d %b %Y %H:%M:%S GMT", :strftime) # Wed, 16 Sep 2024 14:14:58 GMT
# 6. Canonical String generation
canonical_string = "#{http_verb},#{content_type},#{content},#{path},#{date}"
# 7. Signature generation
sha1_signature = :crypto.mac(:hmac, :sha, access_key, canonical_string)
signature = Base.encode64(sha1_signature)
# 8. Token generation
auth_token = "APIAuth #{access_key_id}:#{signature}"
Exemplo de geração do token em JavaScript
const crypto = require('crypto')
const moment = require('moment')
const https = require('https')
// Setup do access_key
let access_key = 'some access key'
let access_key_id = 'some access key id'
let http_verb = 'GET' // Passo 1
let content_type = 'application/json'; // Passo 2
let body = `{ "some_key": "some value" }`
let content = crypto.createHash('md5').update(body).digest('base64') // Passo 3
let path = '/api/v2/partners/readers/<reference_id>' // Passo 4
let date = moment().utc().format("ddd, DD MMM YYYY HH:mm:ss") + " GMT"; // Passo 5
let canonical_string = [http_verb, content_type, content, path, date].join() // Passo 6
let signature = crypto.createHmac('sha1', access_key).update(canonical_string).digest('base64') // Passo 7
let auth_token = "APIAuth " + access_key_id + ":" + signature; // Passo 8
const options = {
host: 'livros.arvore.com.br',
path: path,
method: 'GET',
// Estes request headers devem ser passados em todas as
// chamadas: GET, POST, PUT ou DELETE
headers: {
'Content-Type': content_type,
'Content-MD5': content,
'DATE': date,
'Authorization': auth_token
}
};
const request = https.request(options, (res) => {
if (res.statusCode !== 200) {
console.error(`Did not get an OK from the server. Code: ${res.statusCode}`);
console.error(`Response headers: ${res.headers}`)
res.resume();
return;
};
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('close', () => {
console.log('Retrieved all data');
console.log(JSON.parse(data));
});
});
request.end();
request.on('error', (err) => {
console.error(`Encountered an error trying to make a request: ${err.message}`);
});