Skip to content

Identity and Access Management (IAM)

The shared.iam package provides a unified system for authentication and authorization across all Alan applications.

Overview

The IAM system is built around three core concepts:

  1. Authentication Context - Tracks who is making a request (the "principal") and on whose behalf
  2. Auth Context Providers - Extract authentication information from incoming requests
  3. Access Policies (ABAC) - Define and enforce fine-grained access control rules
flowchart LR
    A[Request] --> B[AuthContextProvider]
    B --> C[AuthContext]
    C --> D[AccessPolicy]

    B -.- B1["Extract auth from headers"]
    C -.- C1["Store principal info"]
    D -.- D1["Enforce access rules"]
Hold "Alt" / "Option" to enable pan & zoom

Key Components

AuthPrincipal

A principal is any entity that can be authenticated - members, alaners, external contractors, service accountsโ€ฆ All authenticatable models must implement the AuthPrincipal mixin:

from shared.iam.auth_principal import AuthPrincipal, AuthPrincipalType
from shared.models.orm.base import BaseModel


class User(AuthPrincipal, BaseModel):
    __auth_principal_type__ = AuthPrincipalType.front_office
    __identifier_column__ = "email"  # Column used for lookups

    @property
    def is_active(self) -> bool:
        return not self.deleted

    @property
    def principal_name(self) -> str:
        return self.full_name

Principal Types:

  • front_office - End users (members, company admins)
  • back_office - principals with an AlanEmployee entry (Alaners, contractors, service accounts)

AuthContext

The AuthContext is a frozen dataclass that stores authentication state for each request. It tracks:

  • Real principal - The actual actor performing the action
  • Effective principal - The subject of the action (same as real, or an impersonated user)
  • Delegate principal - Optional principal acting on behalf of the real principal
  • Session info - Session ID, scopes, and metadata

Never create AuthContext manually

Always access the auth context via current_auth_context. The context is managed by auth providers and must never be instantiated directly. Creating an AuthContext manually bypasses security controls and breaks audit trails.

Access it via current_auth_context:

from shared.iam.helpers import current_auth_context

# Check authentication status
if current_auth_context.is_authenticated:
    user = current_auth_context.real_principal_as(User)
    print(f"Request by {user.email}")

# Check for impersonation
if current_auth_context.is_impersonated:
    actor = current_auth_context.real_principal  # Alaner or ExternalUser
    subject = current_auth_context.effective_principal  # Impersonated user

See Authentication Context โง‰ for detailed documentation.

Auth Context Providers

Providers extract authentication information from incoming requests (JWT tokens, cookies, headers) and set up the AuthContext. They're evaluated in a chain until exactly one matches.

Default setup: The default provider chain is configured at app initialization via CustomApi.register_default_auth_context_providers(). Most blueprints inherit this default.

Blueprint customization: Individual blueprints can override the chain:

  • In the CustomBlueprint constructor via auth_context_providers parameter
  • During blueprint registration
from shared.api.custom_smorest_blueprint import CustomBlueprint
from shared.iam.auth_context.providers.zero_trust import ZeroTrustAuthContextProvider
from shared.iam.auth_context.providers.anonymous import AnonymousAuthContextProvider
from apps.eu_tools.alan_home.models.alaner import Alaner

# Blueprint with custom auth providers
public_blueprint = CustomBlueprint(
    "public",
    __name__,
    auth_context_providers=[
        ZeroTrustAuthContextProvider(Alaner),
        AnonymousAuthContextProvider(),  # Allow unauthenticated access
    ],
)

See Authentication Context โง‰ for provider documentation.

Access Policies (ABAC)

Attribute-Based Access Control policies define who can do what. Policies are generally enforced using the @enforce_policy decorator:

from shared.iam.abac.access_policy import AccessPolicy, enforce_policy


class DocumentOwnerPolicy(AccessPolicy):
    """Only document owners can access their documents"""
    policy_id = "document-owner"

    @classmethod
    def evaluate(cls, document_id: int) -> bool:
        doc = get_document(document_id)
        return doc.owner_id == current_auth_context.effective_principal.id


@enforce_policy(DocumentOwnerPolicy)
def get_document(document_id: int) -> Document:
    return get_or_404(Document, document_id)

See Access Control โง‰ for detailed ABAC documentation.

Quick Reference

Component Purpose Key Import
current_auth_context Access current request's auth info from shared.iam.helpers import current_auth_context
set_auth_context Set auth context (for providers) from shared.iam.helpers import set_auth_context
AuthContextProvider Base class for auth extraction from shared.iam.auth_context.providers.base import AuthContextProvider
AccessPolicy Base class for access rules from shared.iam.abac.access_policy import AccessPolicy
enforce_policy Decorator to enforce policies from shared.iam.abac.access_policy import enforce_policy

Reference