Developer¶
Before Committing¶
Before you push your code to the remote repository, install commitizen
.
Then, install the pre-commit hooks using:
Now you can add your changes with git add <filename.py>
to stage them for committing.
When ready to push the commit, run:
Respository Structure¶
The chime-frb-api has four major distinctive components:
- core manages the authentication and the HTTP query to the backend.
- modules are individual sets of API calls, generally mapping to a sanic blueprint.
- backends are a collection of modules. They offer a singular object with all services availaible through a backend.
- tests can be both for a backend or an individual module.
JWT Tokens¶
Access Tokens¶
Simply put, an ACCESS_TOKEN
is a string with a bunch of characters that are used as credentials, to grant access to resources. More generally they are JSON Web Tokens.
ACCESS_TOKEN
is
- Just a
JWT
! - Disposable, i.e. they can be generated on-demand and in unlimited quantities.
- Valid for only a short period, ~30 minutes.
- Unrevokable, i.e. if you have an access token, and it is valid - the CHIME/FRB backend will process your request
Example
On closer inspection, ACCESS_TOKEN
consists of three parts separated by a period:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
eyJ1c2VyX2lkIjoiZGVidWciLCJleHAiOjE1NzQ0NjE2ODcsImlhdCI6MTU3NDQ1OTg4N30
wHVjUpZRINR0wLaxhLNOPMX3rJbVaicI4J-vNkJOGDM
In order of appearance, these parts are the Header
, Payload
, and the Signature
.
Header
Contains information on how the JWT was encoded and is used to decode the payload.
Payload
contains key/value
pairs of information. Each one of these is called a claim
.
In this example, there are four claims
passed through the JWT
:
user_id
- Name of the user who the token was issued toexp
- ctime at which this token will expireiat
- ctime at which the token was issued atiss
- Issuer of the token, i.e.frb-master
In the future, backends
will support more complex claims as well, e.g. scopes
, rate
or audiences
for requests.
Signature
Contains some hot mess of characters that can only be decoded by the server which issued the token. The server uses a secret passphrase and the payload to create the signature, thus ensuring that the payload cannot be maliciously altered.
Refresh Tokens¶
Refresh tokens are simply an encrypted alphanumeric keys, generated by the CHIME/FRB backends. Every time an ACCESS_TOKEN
expires, the client needs to re-authenticate with the username/password to create a new ACCESS_TOKEN
. But requiring the user to insert username/password each time an ACCESS_TOKEN
expires or asking them to save credentials in code or as environment variables, is neither safe or convenient. REFRESH_TOKEN
solve this problem.
REFRESH_TOKEN
is
- NOT a
JWT
, rather its just a universally unique identifiers - Stored by the backend on a per
user
basis - Used to generate a new
ACCESS_TOKEN
when sent along with active or expiredACCESS_TOKEN
.
Note
When you generate a new ACCESS_TOKEN
using your credentials, it invalidates the currently issued tokens.
Generate Tokens¶
Generating a new set tokens requires CHIME credentials. When successfull, the backend responds with an ACCESS_TOKEN
and REFRESH_TOKEN
. Here is a code agnostic example,
Request
Response
Validate Tokens¶
REFRESH_TOKEN
and ACCESS_TOKEN
work together to provide a friendly, yet secure and authentication environment. To check, whether an ACCESS_TOKEN
is valid, you can use the verify endpoint,
Request
Response
Refresh Tokens¶
In order acquire a new ACCESS_TOKEN
given an existing REFRESH_TOKEN
and ACCESS_TOKEN
you can use the refresh endpoint,
Request
Use Tokens¶
To authenticate, all you need to do is attach the authorization header to a HTTP Request
Request
Response
Example¶
Complete example in Python, using the requests package.
Code
import requests
base_url = "https://frb.chimenet.ca/frb-master"
payload = {"username": "<USERNAME>", "password": "<PASSWORD>"}
# Acquire tokens from frb-master
response = requests.post(url=base_url + "/auth", json=payload)
response.raise_for_status()
tokens = response.json()
access_token = response.json().get("access_token")
refresh_token = response.json().get("refresh_token")
# Verify access token
authorization = {"Authorization": access_token}
response = requests.get(url=base_url + "/auth/verify", headers=authorization)
response.raise_for_status()
print(response.json())
# Refresh access_token
refresh_payload = {"refresh_token": refresh_token}
response = requests.post(
url=base_url + "/auth/refresh", headers=authorization, json=refresh_payload
)
response.raise_for_status
access_token = response.json().get("access_token")