authorization SDK used to build protected Web APIs
Project description
web-auth-sdk
The web-auth-sdk is an authorization SDK that is used to build protected Web APIs. It provides the ability to intercept incoming requests and inject custom logic for authentication and authorization before the request reaches the view function.
In addition, it supports Google OAuth2 for logging in and session logging in.
To access protected APIs, clients should authenticate by passing authorizations. For example, a JWT key can be used as follows:
curl 'http://api.example.com/resources' -H 'Authorization: Bearer eyJ1c2VyX2lkIjoxLCJwZXJtaXNzaW9uX2JpdG'
curl 'http://api.example.com/resources?access_token=eyJ1c2VyX2lkIjoxLCJwZXJtaXNzaW9uX2JpdG'
curl 'http://api.example.com/resources' --cookie 'access_token=eyJ1c2VyX2lkIjoxLCJwZXJtaXNzaW9uX2JpdG'
TIP: When utilizing FastAPI, click the lock symbol on Swagger UI to include your JWT. Run
make startup
for a quick preview.
Requirements
- Python 3.8+
- FastAPI 0.80+ (recommended)
- Django 4.0+ (optional)
- Flask 2.0+ (optional)
Installation
pip install web-auth-sdk
or
git clone https://github.com/yangaound/web-auth-sdk
cd web-auth-sdk && poetry install
Permission Representation
-
Permission list, located at
usr/etc/permissions.json
file:permissions = [ {'bitmask_idx': 0, 'codename': 'add_order', 'name': 'Can add order', 'service': 'order'}, {'bitmask_idx': 1, 'codename': 'change_order', 'name': 'Can change order', 'service': 'order'}, {'bitmask_idx': 2, 'codename': 'delete_order', 'name': 'Can delete order', 'service': 'order'}, {'bitmask_idx': 3, 'codename': 'view_order', 'name': 'Can view order', 'service': 'order'}, {'bitmask_idx': 4, 'codename': 'add_tickettype', 'name': 'Can add ticket type', 'service': 'order'}, {'bitmask_idx': 5, 'codename': 'change_tickettype', 'name': 'Can change ticket type', 'service': 'order'}, {'bitmask_idx': 6, 'codename': 'view_tickettype', 'name': 'Can view ticket type', 'service': 'order'}, {'bitmask_idx': 7, 'codename': 'delete_tickettype', 'name': 'Can delete ticket type', 'service': 'order'}, ]
-
How to grant permissions?
Permissions are encoded using a bitmask of length n that is a multiple of 24. Each permission is represented by a 1 on the corresponding
bitmask_idx
-th position in the bitmask, indicating that the permission is granted. -
Base64-encoded the bitmask
Bitmask Base64-encoded 111111111111111111111111111111110111111101111111 /////39/ -
Decoded/Encoded JWT
{ "user_id": 1, "permission_bitmask": "/////39/", "iat": 1678798980, "exp": 1678800187 }
eyJ1c2VyX2lkIjoxLCJwZXJtaXNzaW9uX2JpdG1hc2siOiIvLy8vLzM5LyIsImlhdCI6MTY3ODc5ODk4MCwiZXhwIjoxNjc4ODAwMTg3fQ
Development
-
FastAPI
import web_auth @fastapi.get('/tickets') @web_auth.permissions('view_ticket') # Iterable[str] are acceptable async def list_tickets() -> list: return []
-
Django
import web_auth from web_auth.django import DjangoBridge web_auth.configure(bridge_class=DjangoBridge) @web_auth.permissions('view_ticket') def list_tickets(request): pass urlpatterns = [django.urls.path('list-tickets', list_tickets)]
-
Flask
import web_auth from web_auth.flask import FlaskBridge web_auth.configure(bridge_class=FlaskBridge) @flask.route('/tickets', methods=['GET']) @web_auth.permissions('view_ticket') def list_tickets() -> list: return []
-
Use instanced context
import web_auth context = web_auth.make_context() @fastapi.get('/tickets') @context.permissions('view_ticket') async def list_tickets() -> list: return []
-
Implement access control & retrieve the consumer info
import fastapi import web_auth context = web_auth.make_context() @fastapi.get('/profile') @context.permissions() def get_profile(request: fastapi.Request, consumer: web_auth.Consumer) -> web_auth.JWTConsumer: # raise `web_auth.AuthException` if the consumer does not have permission context.bridge.access_control( request=request, permissions={'view_ticket'}, aggregation_type=web_auth.PermissionAggregationTypeEnum.ALL, ) return web_auth.JWTConsumer(**consumer.dict())
-
Customization
- Permission Storage
from typing import Optional import fastapi import requests from web_auth import make_context, Storage, PermissionModel, Context class RESTStorage(Storage): def __init__(self, ttl: int, url: str, context: Optional[Context] = None): self.url = url super().__init__(ttl=ttl, context=context) def _load_permissions(self) -> list[PermissionModel]: return [PermissionModel(**r) for r in requests.get(self.url).json()] my_context = make_context( storage_class=RESTStorage, storage_params={'ttl': 60, 'url': 'http://api.example.com/permissions?format=json'}, ) @fastapi.get('/tickets') @my_context(['view_ticket', 'change_ticket']) def get_tickets() -> list[object]: pass
- Authentication
import fastapi from web_auth import make_context, Config, Consumer from web_auth.fastapi import FastapiBridge class MyConsumer(Consumer): user_id: int class MyFastapiBridge(FastapiBridge): def authenticate(self, request: fastapi.Request) -> tuple[MyConsumer, str]: # your authenticate logic return MyConsumer(user_id=1), 'JWT' my_context = make_context( bridge_class=MyFastapiBridge, storage_class=Config.DEFAULT_STORAGE_CLASS, storage_params=Config.DEFAULT_STORAGE_PARAMS, ) @fastapi.get('/profile') @my_context([]) def get_profile(consumer: Consumer) -> MyConsumer: return consumer
- Authorization
import fastapi from web_auth import make_context, Authorization, JWTConsumer, PermissionAggregationTypeEnum from web_auth.fastapi import FastapiBridge class MyAuthorization(Authorization): def authorize( self, consumer: JWTConsumer, permissions: set[str], aggregation_type: PermissionAggregationTypeEnum, ): permission_models = self.context.storage.get_permissions() # Checks whether the `consumer` has the `permissions` in `permission_models` class MyFastapiBridge(FastapiBridge): authorization_class = MyAuthorization my_context = make_context( bridge_class=MyFastapiBridge, ) @fastapi.get('/tickets') @my_context(['view_ticket', 'change_ticket']) def get_tickets() -> list[object]: pass
-
Oauth2 client
- Install apps to
settings.py
INSTALLED_APPS = [ 'web_auth.django' ]
- Register url to
urls.py
urlpatterns = [ django.urls.path('', django.urls.include('web_auth.django.urls')), ]
- Login with Google
- Session Login
- Install apps to
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file web_auth_sdk-1.0.1.tar.gz
.
File metadata
- Download URL: web_auth_sdk-1.0.1.tar.gz
- Upload date:
- Size: 13.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.6.1 CPython/3.9.17 Linux/5.15.0-1041-azure
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 6bf108c088ed449e953fc05d96f36683db798f8a0b5003511e2049076255844d |
|
MD5 | b7a8e82760b380e4a2ef10ff25a7f7c9 |
|
BLAKE2b-256 | 4bb87e11bc1b48a538d24ccdac370ee0d5fb206185d27af863bede16b707bf9f |
File details
Details for the file web_auth_sdk-1.0.1-py3-none-any.whl
.
File metadata
- Download URL: web_auth_sdk-1.0.1-py3-none-any.whl
- Upload date:
- Size: 17.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.6.1 CPython/3.9.17 Linux/5.15.0-1041-azure
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 9de4a99e0ff27fd0785bf2f7b14609c16461076ee09538da19fcd9751924335c |
|
MD5 | 6ef2af314964505ba7d6092c307b3ea6 |
|
BLAKE2b-256 | 662279e6fb82ec18f85004e866744155c433818193ea7332948dd8b505b06139 |