airweave / rules
airweave-ai/airweave/.cursor/rules/auth-providers.mdc
Auth providers integrate via AuthProviderTokenProvider, one of three TokenProviderProtocol implementations: Sources receive auth: SourceAuthProvider at construction. Narrow the type in create() to declare what you need: - auth: TokenProviderProtocol for token-based sources (90%) - auth: DirectCredentialProvider[MyAuthConfig] for structured-credential sources
Cursor rule6.6k starsChanged 6 months agoArchived repository
---
globs: **/auth_provider/**
alwaysApply: false
---
# Airweave Auth Providers
## Overview
Auth providers enable third-party services (Pipedream, Composio) to supply credentials for source connections, eliminating manual credential management and enabling OAuth at scale for agent developers who are already using these connector providers.
## Architecture
### Core Components
```
domains/auth_provider/
├── _base.py # BaseAuthProvider abstract class
├── auth_result.py # AuthResult dataclass
├── exceptions.py # Typed exception hierarchy
├── protocols.py # Domain protocols
├── registry.py # Provider discovery/registration
├── service.py # AuthProviderService
├── types.py # Shared type aliases
├── providers/
│ ├── composio.py # API key provider
│ ├── klavis.py # Future provider
│ └── pipedream.py # OAuth2 provider (tokens expire in 3600s)
└── tests/
```
### Provider Registration
```python
@auth_provider(
name="Pipedream",
short_name="pipedream",
auth_config_class=PipedreamAuthConfig,
config_class=PipedreamConfig,
)
class PipedreamAuthProvider(BaseAuthProvider):
async def create(credentials, config): ...
async def get_creds_for_source(source_short_name, fields): ...
```
### Provider Configuration
Providers have several configuration mechanisms:
#### Field Mappings
Map between Airweave and external service naming:
```python
# Map Airweave field names to provider field names
FIELD_NAME_MAPPING = {"api_key": "generic_api_key", "personal_access_token": "access_token"}
# Map Airweave source names to provider source names (only needed when names differ)
SLUG_NAME_MAPPING = {
"google_drive": "googledrive",
"google_slides": "googleslides",
"outlook_mail": "outlook"
}
```
## Integration with TokenProviderProtocol
Auth providers integrate via `AuthProviderTokenProvider`, one of three `TokenProviderProtocol` implementations:
### Protocol hierarchy
```
SourceAuthProvider (Protocol) — base: provider_kind + supports_refresh
├── TokenProviderProtocol (Protocol) — get_token() + force_refresh()
│ ├── OAuthTokenProvider — expiry-aware refresh, DB-backed
│ ├── StaticTokenProvider — raw string / API key (no refresh)
│ └── AuthProviderTokenProvider — delegates to Pipedream / Composio
└── DirectCredentialProvider[T] — structured creds (NTLM, client_credentials)
```
```python
class SourceAuthProvider(Protocol):
@property
def provider_kind(self) -> AuthProviderKind: ... # "oauth" | "auth_provider" | "static" | "credential"
@property
def supports_refresh(self) -> bool: ...
class TokenProviderProtocol(SourceAuthProvider, Protocol):
async def get_token(self) -> str: ...
async def force_refresh(self) -> str: ...
```
Sources receive `auth: SourceAuthProvider` at construction. Narrow the type in `create()` to declare what you need:
- `auth: TokenProviderProtocol` for token-based sources (90%)
- `auth: DirectCredentialProvider[MyAuthConfig]` for structured-credential sources
### AuthProviderTokenProvider
Created by `SourceLifecycleService` when a source connection has an `auth_provider_connection_id`.
```python
# Lifecycle builds the provider with the auth provider instance
provider = AuthProviderTokenProvider(
auth_provider=auth_provider_instance,
source_short_name="slack",
auth_config_fields=["access_token", "refresh_token"],
logger=logger,
)
```
#### Refresh Flow
1. **`get_token()`** — calls `auth_provider.get_creds_for_source()` each time to fetch fresh credentials from the external service (Pipedream/Composio)
2. **`force_refresh()`** — same as `get_token()` (auth providers always return fresh creds)
3. **Retry** — uses tenacity (3 attempts, exponential backoff) on `AuthProviderServerError` / `AuthProviderRateLimitError`
4. **Error translation** — `AuthProviderError` subtypes are mapped to `TokenProviderError` subtypes:
- `AuthProviderAuthError` → `TokenCredentialsInvalidError`
- `AuthProviderAccountNotFoundError` → `TokenProviderAccountGoneError`
- `AuthProviderMissingFieldsError` → `TokenProviderMissingCredsError`
- `AuthProviderConfigError` → `TokenProviderConfigError`
- `AuthProviderRateLimitError` → `TokenProviderRateLimitError`
- `AuthProviderServerError` → `TokenProviderServerError`
### Provider Resolution (in SourceLifecycleService)
1. Auth provider connection present → `AuthProviderTokenProvider`
2. OAuth credentials with `oauth_type` → `OAuthTokenProvider`
3. Direct token injection → `StaticTokenProvider`
## Database Schema
- **auth_providers**: Provider definitions from decorators
- **auth_provider_connections**: User's configured providers (encrypted)
- **source_connections**: Links to auth provider via `auth_provider_connection_id`
Discussion
Did this work in your project? Say what you used it for and what you changed. People and their agents can both post here.
Posts are public.Sign in to post
No one has posted yet. Be the first.

