Authentication¶
OAuth2 and OpenID Connect authentication for Python applications. Validate your OAuth/OIDC configuration via CLI before integrating into your code. Tokens are stored securely using Secrets (SOPS encryption with age/GPG/KMS).
Note
This module focuses on authentication validation and token acquisition. It does not include a REST client wrapper. Once authenticated, use the obtained tokens with your preferred HTTP library (httpx, requests, etc.).
TL;DR¶
from kstlib.auth import OIDCProvider, AuthSession
provider = OIDCProvider.from_config("corporate")
# Recommended: AuthSession with automatic token handling
with AuthSession(provider) as session:
response = session.get("https://api.company.com/data")
# CLI login
kstlib auth login corporate
kstlib auth status
kstlib auth whoami
# Validate token with cryptographic proof
kstlib auth check corporate --verbose
Key Features¶
Config-driven: Define providers in
kstlib.conf.yml, instantiate with one lineAuto-discovery: OIDC providers automatically fetch endpoints from issuer
PKCE by default: Secure authorization flow without client secrets
SOPS token storage: Tokens encrypted via Secrets (age/GPG/KMS)
Token validation:
kstlib auth checkprovides cryptographic proof that JWT tokens are validCLI included:
kstlib auth login|logout|status|token|whoami|providers|checkToken refresh: Automatic refresh before expiration
Quick Start¶
# kstlib.conf.yml
auth:
default_provider: corporate
providers:
corporate:
type: oidc
issuer: https://sso.company.com/realms/main
client_id: my-app
pkce: true
# Login via browser
kstlib auth login corporate
# Check status
kstlib auth status
from kstlib.auth import OIDCProvider
provider = OIDCProvider.from_config("corporate")
token = provider.get_token()
headers = {"Authorization": f"Bearer {token.access_token}"}
How It Works¶
Supported Protocols¶
Protocol |
Status |
Description |
|---|---|---|
OAuth2 |
Supported |
Authorization Code flow with manual endpoint configuration |
OIDC |
Supported |
OpenID Connect with auto-discovery ( |
PKCE |
Supported |
Proof Key for Code Exchange (recommended for all flows) |
Authentication Flow¶
1. Provider generates authorization URL with PKCE challenge
2. User authenticates in browser
3. Callback receives authorization code
4. Provider exchanges code for tokens (auto uses PKCE verifier)
5. Tokens stored securely (SOPS, file, or memory)
6. Token auto-refreshed before expiration
Architecture¶
┌─────────────────────────────────────────────────────────────┐
│ kstlib.auth │
├─────────────────────────────────────────────────────────────┤
│ Providers │ Storage │ CLI │
│ ├─ OAuth2Provider │ ├─ MemoryStorage │ ├─ check │
│ └─ OIDCProvider │ ├─ FileStorage │ ├─ login │
│ │ └─ SOPSStorage │ ├─ logout │
│ Validation │ │ ├─ status │
│ └─ TokenChecker │ Config │ ├─ token │
│ │ └─ auth: section │ ├─ whoami │
│ Models │ in conf.yml │ └─ providers │
│ ├─ Token │ │ │
│ └─ AuthFlow │ │ │
└─────────────────────────────────────────────────────────────┘
Configuration¶
Basic OIDC provider¶
auth:
providers:
corporate:
type: oidc
issuer: https://sso.company.com/realms/main
client_id: my-app
scopes: [openid, profile, email]
pkce: true
OAuth2 provider (manual endpoints)¶
auth:
providers:
github:
type: oauth2
authorize_url: https://github.com/login/oauth/authorize
token_url: https://github.com/login/oauth/access_token
client_id: your-client-id
client_secret: your-client-secret
scopes: [read:user, user:email]
Token storage¶
auth:
token_storage: sops # or "file" or "memory"
sops:
path: ~/.config/kstlib/tokens.sops.yml
See Configuration for complete options.
Common Patterns¶
Authenticated API requests¶
from kstlib.auth import OIDCProvider, AuthSession
provider = OIDCProvider.from_config("corporate")
with AuthSession(provider) as session:
response = session.get("https://api.company.com/data")
# Token injected automatically, auto-refresh on expiration
Login flow in CLI app¶
from kstlib.auth import OIDCProvider
provider = OIDCProvider.from_config("corporate")
if not provider.is_authenticated:
provider.login() # Opens browser, waits for callback
userinfo = provider.get_userinfo()
print(f"Welcome, {userinfo['name']}!")
Multiple providers¶
from kstlib.auth import OIDCProvider, OAuth2Provider, AuthSession
corporate = OIDCProvider.from_config("corporate")
github = OAuth2Provider.from_config("github")
# Use different sessions for different services
with AuthSession(corporate) as corp_session:
corp_response = corp_session.get("https://api.company.com/data")
with AuthSession(github) as gh_session:
gh_response = gh_session.get("https://api.github.com/user")
Troubleshooting¶
“Not authenticated”¶
User needs to log in:
kstlib auth login corporate
Token expired¶
Tokens should auto-refresh. If not:
token = provider.get_token(auto_refresh=True) # Force refresh check
# or
provider.refresh_token() # Explicit refresh
PKCE errors¶
Ensure PKCE is enabled consistently:
auth:
providers:
corporate:
pkce: true # Must match IdP configuration
Discovery failed¶
Check issuer URL has /.well-known/openid-configuration:
curl https://sso.company.com/realms/main/.well-known/openid-configuration
Out of Scope¶
The following protocols are not supported:
Protocol |
Reason |
|---|---|
SAML 2.0 |
XML-based enterprise legacy protocol |
Kerberos |
Active Directory / on-premise authentication |
LDAP |
Directory-based authentication |
Basic Auth |
Insecure, no token management needed |
Next Steps¶
Quickstart - Get authenticated in 5 minutes
Configuration - Configure providers in
kstlib.conf.ymlProviders - OAuth2 vs OIDC provider details
CLI Reference - Command-line interface reference
Token Storage - Secure token storage with SOPS
API Reference¶
Full autodoc: Authentication
Class |
Description |
|---|---|
|
OpenID Connect with auto-discovery |
|
Manual OAuth2 configuration |
|
6-step JWT token validation with cryptographic proof |
|
Token object with access/refresh/id tokens |
|
HTTP session (httpx) with auto token injection and refresh |