In order to sustain the highest security standards in terms of authorization and authentication, while simplifying implementation, and providing you with control over your identities, we have adopted JWT based OAuth2.0 authorization using assertions as authorization grants (as specified in RFC7521 and RFC7523).
To access Noa’s API, you need to register your client application by creating client application identifiers through our API. You are free to create and organize client application credentials as you see fit. Our recommendation is to at least create one client application identifier for each separate department or service accessing Noa’s APIs.
At creation time, the private key of the pair will be handed to you, while our system keeps the public key. We do not keep a copy of your private key, so it can only be delivered at creation time. Note that this key is meant to live where secrets can be kept, within non-publicly-accessible part of your backends. You have full control of the lifecycle of your keys, being able to delete existing keys and establish your own key rotation policy.
The list of scopes will increase over time, you will be able to update the scopes at any time consuming our REST API.
bicycle:read
bicycle:write
trip:read
organization:read
support-ticket:read
support-ticket:write
Requisites
- You need to be a fleet operator of the fleet you plan to register a client application for.
- You need a working Python environment. We encourage the installation of Python using pyenv
- Then work within a Python virtual environment
How to register a client application?
Go to the FMS's Organization Settings Page and register your third party application in the API Access
section.
Once a private key is in your domain, the authentication and authorization process works as follows:
- Create the authorization assertion, and sign it with your private key.
- Request a token using the security token service endpoint, include access metadata and your newly created signature.
- Use the access token provided back to you to access different services on Noa’s APIs. To do that, include an
Authorization
header within the token, and version of the API that you intend to consume. For example:Authorization: JWT <token>
- When your token expires, repeat the process to create a new assertion, and obtain a new JWT token.
How to generate an assertion to obtain a token from our Security Token Service?
In these examples, python3.6 is used and you will need to install third party libraries as follow:
$ pip install requests "pyjwt[crypto]"
Python
import datetime as dt
import jwt
with open('your-app-pkey.pem', 'rb') as open_file:
private_key = open_file.read()
now = dt.datetime.utcnow()
organization_uuid = '<your-org-uuid>'
name = 'my shiny backend'
payload = {'iss': name,
'organization': organization_uuid,
'exp': now + dt.timedelta(minutes=10),
'iat': now}
assertion = jwt.encode(payload, private_key, algorithm='ES512')
Go
package main
import (
"crypto/x509"
"github.com/dgrijalva/jwt-go"
"time"
"fmt"
"encoding/pem"
)
type assertion struct {
Assertion string `json:"assertion"`
}
func main() {
now := time.Now().UTC()
keyString := `-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----`
block, err := pem.Decode([]byte(keyString))
log.Fatal(err)
}
privateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil{
log.Fatal(err)
}
token := jwt.NewWithClaims(jwt.SigningMethodES384, jwt.MapClaims{
"iss": "my shiny backend",
"organization": "<your org uuid>",
"exp": now.Add(time.Duration(10)*time.Minute).Unix(),
"iat": now.Unix()})
assertion, _ := token.SignedString(privateKey)
}
How to obtain a JWT token on behalf of your client application?
import json
import requests
response = requests.post(
'https://sts.lock8.me/jwt',
data=json.dumps({'assertion': assertion.decode()}))
jwt = response.json()['jwt']
You can now use this JWT token to access all services provided by Noa.
How do I consume the JWT token against all Noa services?
You can now insert the newly obtained JWT token into the Authorization header.
Authorization: JWT {your jwt token}
import requests
response = requests.get(
'https://api.lock8.me/api/bicycles/'
headers={'Authorization': f'JWT {jwt}',
'Accept': 'application/json; version=1.0'})
assert response.status_code == 200
More details in the chapter Consuming the API