Skip to main content

API key authentication library using Superfunctions abstractions for Python

Project description

authfn Python SDK

API key authentication library using Superfunctions abstractions for Python

Python implementation of authfn with async/await support for API key-based authentication.

Overview

authfn is a reference implementation of authentication that provides API key-based authentication. It includes:

  • Auth Provider: Async authentication and authorization
  • Database Storage: Uses database adapters for storing API keys
  • Key Management: Secure API key generation and validation
  • Type Safety: Full type hints with Pydantic models

Installation

pip install authfn

Quick Start

1. Setup Database

You'll need a database adapter that implements the DatabaseAdapter protocol:

from authfn.types import DatabaseAdapter, WhereClause, OrderByClause
from typing import Any, Dict, List, Optional


class MyDatabaseAdapter:
    """Your database adapter implementation."""
    
    async def find_one(
        self,
        model: str,
        where: List[WhereClause],
        namespace: str,
    ) -> Optional[Dict[str, Any]]:
        # Your implementation here
        pass
    
    async def find_many(
        self,
        model: str,
        where: List[WhereClause],
        order_by: Optional[List[OrderByClause]],
        namespace: str,
    ) -> List[Dict[str, Any]]:
        # Your implementation here
        pass
    
    async def create(
        self,
        model: str,
        data: Dict[str, Any],
        namespace: str,
    ) -> None:
        # Your implementation here
        pass
    
    async def update(
        self,
        model: str,
        where: List[WhereClause],
        data: Dict[str, Any],
        namespace: str,
    ) -> None:
        # Your implementation here
        pass

2. Create authfn Instance

from authfn import create_authfn, AuthFnConfig

adapter = MyDatabaseAdapter()

auth = create_authfn(
    AuthFnConfig(
        database=adapter,
        namespace="authfn",
        enable_api=True,
        api_config={
            "admin_key": "your-admin-key",  # Optional: protect management API
        },
    )
)

3. Create API Keys

from authfn.types import ApiKeyCreate

# Create a new API key
result = await auth.create_key(
    ApiKeyCreate(
        name="Production API Key",
        resourceIds=["resource-1", "resource-2"],
        scopes=["read", "write"],
        metadata={"environment": "production"},
    )
)

print(f"API Key ID: {result.id}")
print(f"API Key: {result.key}")  # Save this securely!

4. Authenticate Requests

from authfn.types import Request

class MyRequest:
    """Your request wrapper."""
    
    def __init__(self, headers: Dict[str, str]):
        self._headers = headers
    
    @property
    def headers(self) -> Dict[str, str]:
        return self._headers


# Authenticate a request
request = MyRequest({"Authorization": "Bearer ak_..."})

try:
    session = await auth.provider.authenticate(request)
    if session:
        print(f"Authenticated as: {session.name}")
        print(f"Resource IDs: {session.resource_ids}")
        print(f"Scopes: {session.scopes}")
except Exception as e:
    print(f"Authentication failed: {e}")

5. Authorize Resource Access

# Check if session has access to a resource
if session:
    has_access = await auth.provider.authorize(session, "resource-1")
    if has_access:
        print("Access granted to resource-1")
    else:
        print("Access denied to resource-1")

6. Manage API Keys

# Get API key by ID
key = await auth.get_key("key_...")
if key:
    print(f"Key name: {key.name}")
    print(f"Created at: {key.created_at}")

# List all API keys
keys = await auth.list_keys()
for key in keys:
    print(f"- {key.name} ({key.id})")

# List keys for a specific resource
keys = await auth.list_keys(filters={"resourceId": "resource-1"})

# Revoke an API key
await auth.revoke_key("key_...")

Complete Example

import asyncio
from authfn import create_authfn, AuthFnConfig
from authfn.types import ApiKeyCreate


async def main():
    # Setup (you would use your actual database adapter)
    adapter = MyDatabaseAdapter()
    
    auth = create_authfn(
        AuthFnConfig(
            database=adapter,
            namespace="authfn",
        )
    )
    
    # Create an API key
    result = await auth.create_key(
        ApiKeyCreate(
            name="My App Key",
            resourceIds=["app-1", "app-2"],
            scopes=["read", "write"],
        )
    )
    
    print(f"Created API key: {result.key}")
    
    # Simulate authentication
    class SimpleRequest:
        def __init__(self, token: str):
            self._headers = {"Authorization": f"Bearer {token}"}
        
        @property
        def headers(self):
            return self._headers
    
    request = SimpleRequest(result.key)
    session = await auth.provider.authenticate(request)
    
    if session:
        print(f"Authenticated as: {session.name}")
        
        # Check authorization
        can_access = await auth.provider.authorize(session, "app-1")
        print(f"Can access app-1: {can_access}")


if __name__ == "__main__":
    asyncio.run(main())

Schema Definition

Get the schema definition for creating database tables:

from authfn.schema import get_schema

schema = get_schema({"namespace": "authfn"})
print(schema)
# {
#   "version": 1,
#   "schemas": [
#     {
#       "modelName": "apiKeys",
#       "fields": {...},
#       "indexes": [...]
#     }
#   ]
# }

API Reference

create_authfn(config: AuthFnConfig) -> AuthFn

Create an authfn instance.

AuthFn

Main authfn class with the following methods:

  • provider: AuthFnProvider - Auth provider for authentication
  • async create_key(data: ApiKeyCreate) -> ApiKeyResponse - Create a new API key
  • async revoke_key(key_id: str) -> None - Revoke an API key
  • async get_key(key_id: str) -> Optional[ApiKeySanitized] - Get an API key by ID
  • async list_keys(filters: Optional[Dict]) -> List[ApiKeySanitized] - List API keys

AuthFnProvider

Auth provider with the following methods:

  • async authenticate(request: Request) -> Optional[ApiKeySession] - Authenticate a request
  • async authorize(session: ApiKeySession, resource_id: str) -> bool - Authorize resource access
  • async revoke(session_id: str) -> None - Revoke a session

Type Safety

The SDK uses Pydantic models for full type safety:

from authfn.types import (
    ApiKey,
    ApiKeyCreate,
    ApiKeyResponse,
    ApiKeySanitized,
    ApiKeySession,
    AuthFnConfig,
)

Error Handling

from authfn.types import (
    InvalidCredentialsError,
    ExpiredCredentialsError,
    UnauthorizedError,
    NotFoundError,
)

try:
    session = await auth.provider.authenticate(request)
except InvalidCredentialsError:
    print("Invalid API key")
except ExpiredCredentialsError:
    print("API key has expired")

Development

# Install dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Type checking
mypy authfn

# Linting
ruff check authfn

# Format code
black authfn

License

MIT

Repository

https://github.com/21nCo/super-functions

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

authfn-0.1.0.tar.gz (26.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

authfn-0.1.0-py3-none-any.whl (9.1 kB view details)

Uploaded Python 3

File details

Details for the file authfn-0.1.0.tar.gz.

File metadata

  • Download URL: authfn-0.1.0.tar.gz
  • Upload date:
  • Size: 26.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for authfn-0.1.0.tar.gz
Algorithm Hash digest
SHA256 17489d8aeb83badaf8d2863e806dff798e93eba130c3dd8fd4986bb0bf0c84c6
MD5 a7b8b6cb2bd35da34c2267691f470076
BLAKE2b-256 8654b87a87049d707b8571e436b772d551fcbe9910a1342088f5d4d50564e0f3

See more details on using hashes here.

File details

Details for the file authfn-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: authfn-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 9.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for authfn-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7c08300158f9189655d710b99a8815c9888813aee092b57645acfacbfae63ee6
MD5 16c3a2378cf82e4d1451f3c4084a74b8
BLAKE2b-256 1402cd518994079b56c5ed1798864db37d86100e8c4f97ff831cd45ce004daf6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page