Skip to main content

web-auth-sdk

CI Status PyPI Version License Python Versions

Authorization SDK for building protected Web APIs. It allows your endpoints to perform custom authorization and authentication before the request reaches the view function. Then it passes the consumer object to the view function for further processing.

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'

TIP: When utilizing FastAPI, click the lock symbol on Swagger UI to include your JWT. Run make startup for a quick preview. img.png

Requirements

  • Python 3.8+
  • FastAPI 0.109.0+ (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

  1. Permission list, located in the 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'},
    ]
    
  2. 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 at the corresponding bitmask_idx-th position in the bitmask, indicating that the permission is granted.

  3. Base64-encoded bitmask

    Bitmask Base64-encoded
    111111111111111111111111111111110111111101111111 /////39/
  4. Decoded/Encoded JWT

    Decoded JWT:

    {
      "user_id": 1,
      "permission_bitmask": "/////39/",
      "iat": 1678798980,
      "exp": 1678800187
    }
    

    Encoded JWT:

    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(bridge_class='web_auth.fastapi.FastapiBridge')
    
    @fastapi.get('/tickets')
    @context.permissions('view_ticket')
    async def list_tickets() -> list: 
        return []
    
  • Retrieve the consumer

    import fastapi
    import web_auth
    
    
    @fastapi.get('/profile')
    @web_auth.permissions(['view_directory'])
    def get_profile(consumer: web_auth.Consumer) -> dict:
        return {
            'user': consumer.user.dict(),
            'directories': 'get_directories(consumer.user.user_id)',
        }
    
  • Implement Fine-Grained Permission Control

    import fastapi
    import web_auth
    
    
    @fastapi.post('/some-action')
    def some_action(request: fastapi.Request):
        # Create a context with fastapi bridge class
        context = web_auth.make_context(bridge_class=web_auth.Config.DEFAULT_BRIDGE_CLASS)
    
        # Authorize access with specific permissions (e.g., 'view_directory')
        # If this request lacks permission, it will raise `web_auth.AuthException`
        _: web_auth.Consumer = context.bridge.access_control(
            request=request, 
            permissions={'view_directory'},
            aggregation_type=web_auth.PermissionAggregationTypeEnum.ALL,
        )
    
        # Do some action
    
  • Customization

    1. 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
    
    1. Authentication and Authenticated Consumer/User
    import pydantic  
    import fastapi
    
    from web_auth import make_context, Consumer
    from web_auth.fastapi import FastapiBridge
    
    
    class AuthenticatedUser(pydantic.BaseModel):
        account: str
    
    
    class MyFastapiBridge(FastapiBridge):
        # Inject your consumer here if it's not inherited from the `web_auth.Consumer`
        consumer_class = Consumer
    
        def authenticate(self, request: fastapi.Request) -> Consumer:
            # Your authenticate logic here
            return Consumer(
                permission_bitmask='11101101111',
                user=AuthenticatedUser(account='52354342/Jack'),
            )
    
    
    my_context = make_context(bridge_class=MyFastapiBridge)
    
    @fastapi.get('/me')
    @my_context([])
    def get_profile(consumer: Consumer) -> AuthenticatedUser:
        return consumer.user
    
    1. Authorization
    import fastapi
    
    from web_auth import make_context, BitmaskAuthorization, Consumer, PermissionAggregationTypeEnum
    from web_auth.fastapi import FastapiBridge 
    
    
    class MyAuthorization(BitmaskAuthorization):
        def authorize(
            self,
            consumer: Consumer,
            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):
        # Inject your Authorization implementation here, it's default to BitmaskAuthorization.
        authorization_class = MyAuthorization
    
    # Configurate your customization
    my_context = make_context(bridge_class=MyFastapiBridge)
    
    @fastapi.get('/tickets')
    @my_context(['view_ticket', 'change_ticket'])
    def get_tickets() -> list[object]:
        pass
    

Metadata

Release files for web-auth-sdk 1.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for web-auth-sdk 1.2.0
File Size Uploaded Provenance Actions
web_auth_sdk-1.2.0.tar.gz 14.0 kB Without provenance Details for web_auth_sdk-1.2.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for web-auth-sdk 1.2.0
File Interpreter ABI Platform Actions
web_auth_sdk-1.2.0-py3-none-any.whl Python 3 none any Details for web_auth_sdk-1.2.0-py3-none-any.whl

Total release size: 31.5 kB

Release files / web_auth_sdk-1.2.0.tar.gz

Download URL web_auth_sdk-1.2.0.tar.gz
Size 14.0 kB
Tags Source
SHA-256 checksum
How to use checksums
9d5cbcf25b3beb37492b283593ec99cd94c314fbeeb9bfbb3930638d43e2bb77
BLAKE2b-256 checksum
How to use checksums
bf8e118251dc48529cf7702c3e6ec18017194789a698daf06f08d14e0da98ab6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.8.3 CPython/3.9.20 Linux/6.8.0-1014-azure

Release files / web_auth_sdk-1.2.0-py3-none-any.whl

Download URL web_auth_sdk-1.2.0-py3-none-any.whl
Size 17.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
46dd32dea5cbf5f595ebd9f060fc05d7f2fe97fb847050fb86430a191add1e97
BLAKE2b-256 checksum
How to use checksums
dc023d4c066c1fb139833e2d17957dac0e94d9135a90783dd2ff4fe3a21648e3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.8.3 CPython/3.9.20 Linux/6.8.0-1014-azure

Security for web-auth-sdk 1.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page