Authorization
For every request to FirecREST you need to have a valid access token. This will enable your application to have access to the requested resources.
The pyFirecREST Authorization Object
You can take care of the access token by yourself any way you want, or even better use a python library to take care of this for you, depending on the grant type.
What pyFirecREST will need in the end is only a python object with the method get_access_token(), that when called will provide a valid access token.
Let’s say for example you have somehow obtained a long-lasting access token. The Authorization class you would need to make and give to Firecrest would look like this:
class MyAuthorizationClass:
def __init__(self):
pass
def get_access_token(self):
return <TOKEN>
If this is your case you can move on to the next session, where you can see how to use this Authorization object, in order to make your requests.
If you want to use the Client Credentials authorization grant, you can use the ClientCredentialsAuth class from pyFirecREST and setup the authorization object like this:
import firecrest as f7t
keycloak = f7t.ClientCredentialsAuth(
<client_id>, <client_secret>, <token_uri>
)
Device Authorization Grant Workflow
When your application cannot open a browser or embed a user-agent, you can use the OAuth 2.0 Device Authorization Grant. In this flow, your app is responsible for:
Requesting a device code & user code from the token endpoint
Instructing the user to visit a verification URL and enter the code
Polling the token endpoint until the user has authorized
Caching and refreshing the access token for future calls
This workflow is not handled by pyFirecREST directly, but you can implement it using the requests library or any other HTTP client of your choice. The Authorization object you hand to pyFirecREST needs the get_access_token() method, but it would also have orchestrate to workflow behind the scenes.
Here we provide an example implementation using requests. We chose to inform the user about the verification URL and user code by simply printing it, but you should adapt this to the needs of your application.
import time
import requests
class DeviceAuthorizationAuth:
def __init__(self, client_id, device_uri, token_uri, scope=None):
self.client_id = client_id
self.device_uri = device_uri
self.token_uri = token_uri
self.scope = scope or "openid"
self._token_data = None
def _start_device_flow(self):
resp = requests.post(self.device_uri, data={
"client_id": self.client_id,
"scope": self.scope,
})
resp.raise_for_status()
return resp.json()
def _poll_for_token(self, device_code, interval, expires_in):
deadline = time.time() + expires_in
while time.time() < deadline:
resp = requests.post(self.token_uri, data={
"grant_type": "urn:ietf:params:oauth:grant-type:device_code",
"device_code": device_code,
"client_id": self.client_id,
})
if resp.status_code == 200:
return resp.json()
time.sleep(interval)
raise RuntimeError("User did not authorize in time")
def get_access_token(self):
# If we already have a (non-expired) token, reuse it
if self._token_data and time.time() < self._token_data["expires_at"]:
return self._token_data["access_token"]
# 1) Start device flow
flow = self._start_device_flow()
print(f"Go to {flow['verification_uri']} and enter code {flow['user_code']}")
# 2) Poll until the user completes authorization
token = self._poll_for_token(
device_code=flow["device_code"],
interval=flow.get("interval", 5),
expires_in=flow.get("expires_in", 600),
)
# 3) Compute absolute expiry & cache
token["expires_at"] = time.time() + token["expires_in"]
self._token_data = token
return token["access_token"]
# Usage with pyFirecREST
import firecrest as f7t
auth = DeviceAuthorizationAuth(
client_id="YOUR_CLIENT_ID",
device_uri="https://auth.example.com/device",
token_uri="https://auth.example.com/token",
scope="openid profile",
)
firecrest = f7t.FirecrestClient(url="https://api.firecrest.example.com", auth=auth)
In a similar way you can reuse other packages to support different grant types, like Flask-OIDC.