Github
The FastApi starter kit leverages the oneloop-python
SDK under the hood, but provides a helpful middleware that can be used for verifying API keys.
You can fork the starter kit repo, or copy the middleware from it.
Installation
pip install typing fastapi oneloop-python
Usage
Middleware
Let’s first add the middleware that will be used to verify the API key. This will save you from having to write the same code in every route.
import json
from typing import List, TypedDict, Optional
from fastapi import Request, HTTPException
from oneloop_client. client import OneloopApi
from oneloop_client. types import VerifyApiKeyResponse, ErrorResponse
class ScopeObject ( TypedDict) :
id : str
create: Optional[ bool ]
read: Optional[ bool ]
update: Optional[ bool ]
delete: Optional[ bool ]
oneloop = OneloopApi( token= "your-oneloop-api-key" )
def oneloop_middleware ( scopes: List[ ScopeObject] = [ ] ) :
async def middleware ( request: Request) :
auth_header = request. headers. get( "authorization" )
if not auth_header:
raise HTTPException( status_code= 401 , detail= "Customer API key is missing" )
verify_request = oneloop. verify_api_key(
key= auth_header. replace( "Bearer " , "" ) ,
requested_scopes= [
{
"id" : scope[ "id" ] ,
"representation" : scope[ "id" ] ,
"read" : scope. get( "read" , False ) ,
"create" : scope. get( "create" , False ) ,
"update" : scope. get( "update" , False ) ,
"delete" : scope. get( "delete" , False ) ,
}
for scope in scopes
]
)
try :
verify_response: VerifyApiKeyResponse = oneloop. verify_api_key( verify_request)
if verify_response. status != "VALID" :
raise HTTPException( status_code= 401 , detail= verify_response. status)
except Exception as e:
error = json. loads( e. body)
code = error[ 'error' ] [ 'code' ]
message = error[ 'error' ] [ 'message' ]
raise HTTPException( status_code= code, detail= message)
return middleware
Authenticate the API key
Now, let’s use the middleware in a FastApi route and authenticate the API key.
@app. get ( "/" , dependencies= [ Depends( oneloop_middleware( ) ) ] )
async def read_root ( ) :
return { "Hello" : "World" }
Checking for permissions
You can also check for permissions in your routes. Let’s say you have a route that requires a specific read access for profile data.
You want to check if the API key has the required scope before returning the data. You can pass that scope to the middleware.
Let’s modify the above route to check for profile
read access.
@app. get ( "/" , dependencies= [ Depends( oneloop_middleware( [ { "id" : "profile" , "read" : True } ] ) ) ] )
async def read_root ( ) :
return { "Hello" : "World" }