Python social authentication framework with 195+ backend providers for OAuth, OpenID Connect, and SAML integration.
—
The strategy interface provides a framework-agnostic layer that adapts social-auth-core to work with any Python web framework. By implementing the strategy pattern, the library can integrate with Django, Flask, Pyramid, FastAPI, or any other web framework while maintaining consistent authentication behavior.
The foundational strategy class that defines the interface for framework integration and provides common functionality.
class BaseStrategy:
"""
Base strategy class for framework integration.
The strategy pattern enables social-auth-core to work with any web framework
by abstracting request/response handling, session management, and storage operations.
"""
# Class constants
ALLOWED_CHARS: str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
DEFAULT_TEMPLATE_STRATEGY: type = None # Template strategy class
SESSION_SAVE_KEY: str = "psa_session_id" # Session key for saving state
def __init__(self, storage=None, tpl=None):
"""
Initialize strategy with storage and template handler.
Parameters:
- storage: Storage backend instance for data persistence
- tpl: Template strategy instance for rendering (optional)
"""
def setting(self, name: str, default=None, backend=None):
"""
Get configuration setting value.
Retrieves setting values with proper prefixing and backend-specific
overrides, following the SOCIAL_AUTH_<BACKEND>_<SETTING> pattern.
Parameters:
- name: Setting name without prefix
- default: Default value if setting not found
- backend: Backend instance for backend-specific settings
Returns:
Setting value or default
"""
def get_setting(self, name: str):
"""
Get raw setting value without defaults.
Parameters:
- name: Full setting name
Returns:
Setting value or None if not found
Raises:
NotImplementedError: Must be implemented by subclasses
"""
def request_data(self, merge=True):
"""
Get request data (GET and POST parameters).
Extracts data from the current HTTP request, typically combining
query parameters and form data into a single dictionary.
Parameters:
- merge: Whether to merge GET and POST data (default: True)
Returns:
Dictionary of request parameters
Raises:
NotImplementedError: Must be implemented by subclasses
"""
def request_host(self):
"""
Get current request host.
Returns:
Host string from current request
Raises:
NotImplementedError: Must be implemented by subclasses
"""
def redirect(self, url: str):
"""
Create redirect response.
Generates a framework-specific redirect response to the specified URL.
Parameters:
- url: URL to redirect to
Returns:
Framework-specific redirect response
Raises:
NotImplementedError: Must be implemented by subclasses
"""
def html(self, content: str):
"""
Create HTML response.
Generates a framework-specific HTML response with the provided content.
Parameters:
- content: HTML content string
Returns:
Framework-specific HTML response
Raises:
NotImplementedError: Must be implemented by subclasses
"""
def render_html(self, tpl=None, html=None, context=None):
"""
Render HTML using template system.
Parameters:
- tpl: Template name/path (optional)
- html: Raw HTML string (optional)
- context: Template context dictionary (optional)
Returns:
Rendered HTML string
"""
def build_absolute_uri(self, path=None):
"""
Build absolute URI from relative path.
Parameters:
- path: Relative path (optional)
Returns:
Absolute URI string
Raises:
NotImplementedError: Must be implemented by subclasses
"""
def absolute_uri(self, path=None):
"""
Alias for build_absolute_uri.
Parameters:
- path: Relative path (optional)
Returns:
Absolute URI string
"""
def get_pipeline(self, backend):
"""
Get authentication pipeline configuration.
Returns the list of pipeline functions to execute for authentication,
allowing per-backend customization of the authentication flow.
Parameters:
- backend: Authentication backend instance
Returns:
Tuple of pipeline function names
"""
def authenticate(self, *args, **kwargs):
"""
Authenticate user with backend.
Executes the authentication process using the specified backend,
handling the complete pipeline execution and user creation/retrieval.
Parameters:
- backend: Authentication backend instance
- Additional arguments for authentication pipeline
Returns:
Authenticated user instance or None
"""
def clean_authenticate_args(self, *args, **kwargs):
"""
Clean and validate authentication arguments.
Processes authentication arguments to ensure they are in the correct
format for the pipeline execution.
Parameters:
- Arguments and keyword arguments for authentication
Returns:
Tuple of (cleaned_args, cleaned_kwargs)
"""
def continue_pipeline(self, partial):
"""
Continue interrupted authentication pipeline.
Resumes authentication flow from a partial pipeline state,
typically after user input or email validation.
Parameters:
- partial: Partial pipeline data object
Returns:
Authentication result or further partial state
"""
def session_get(self, name, default=None):
"""
Get value from session.
Parameters:
- name: Session key name
- default: Default value if key not found
Returns:
Session value or default
Raises:
NotImplementedError: Must be implemented by subclasses
"""
def session_set(self, name, value):
"""
Set value in session.
Parameters:
- name: Session key name
- value: Value to store
Raises:
NotImplementedError: Must be implemented by subclasses
"""
def session_pop(self, name, default=None):
"""
Remove and return value from session.
Parameters:
- name: Session key name
- default: Default value if key not found
Returns:
Session value or default
Raises:
NotImplementedError: Must be implemented by subclasses
"""
def session_setdefault(self, name, value):
"""
Set session value if key doesn't exist.
Parameters:
- name: Session key name
- value: Default value to set
Returns:
Existing value or newly set value
"""
def clean_partial_pipeline(self, token):
"""
Clean partial pipeline data.
Removes stored partial pipeline data after completion or cancellation.
Parameters:
- token: Partial pipeline token to clean
"""
def random_string(self, length=12, allowed_chars=None):
"""
Generate random string.
Creates a random string for tokens, nonces, or other security purposes.
Parameters:
- length: String length (default: 12)
- allowed_chars: Characters to use (default: ALLOWED_CHARS)
Returns:
Random string of specified length
"""
def create_user(self, *args, **kwargs):
"""
Create new user account.
Delegates to storage backend to create a new user with provided details.
Parameters:
- User creation arguments
Returns:
New user instance
"""
def get_user(self, user_id):
"""
Get user by ID.
Parameters:
- user_id: User primary key
Returns:
User instance or None if not found
"""Base class for template rendering strategies that handle HTML output generation.
class BaseTemplateStrategy:
"""
Base template strategy for rendering HTML content.
Provides abstraction for template rendering that can be adapted
to different template engines like Jinja2, Django templates, etc.
"""
def __init__(self, strategy):
"""
Initialize template strategy.
Parameters:
- strategy: Parent strategy instance
"""
def render(self, tpl=None, html=None, context=None):
"""
Render template or HTML string.
Parameters:
- tpl: Template name/path (optional)
- html: Raw HTML string (optional)
- context: Template context dictionary (optional)
Returns:
Rendered HTML string
Raises:
ValueError: If neither tpl nor html provided
"""
def render_template(self, tpl: str, context: dict | None):
"""
Render template file.
Parameters:
- tpl: Template name/path
- context: Template context dictionary
Returns:
Rendered HTML string
Raises:
NotImplementedError: Must be implemented by subclasses
"""
def render_string(self, html: str, context: dict | None):
"""
Render HTML string with context.
Parameters:
- html: Raw HTML string with template syntax
- context: Template context dictionary
Returns:
Rendered HTML string
Raises:
NotImplementedError: Must be implemented by subclasses
"""from django.conf import settings
from django.shortcuts import redirect
from django.http import HttpResponse
from social_core.strategy import BaseStrategy
class DjangoStrategy(BaseStrategy):
"""Django framework strategy implementation."""
def __init__(self, storage, request=None, tpl=None):
self.request = request
super().__init__(storage, tpl)
def get_setting(self, name):
return getattr(settings, name, None)
def request_data(self, merge=True):
if not self.request:
return {}
if merge:
data = self.request.GET.copy()
data.update(self.request.POST)
return data
return self.request.GET if self.request.method == 'GET' else self.request.POST
def request_host(self):
return self.request.get_host() if self.request else ''
def redirect(self, url):
return redirect(url)
def html(self, content):
return HttpResponse(content, content_type='text/html')
def build_absolute_uri(self, path=None):
return self.request.build_absolute_uri(path) if self.request else path
def session_get(self, name, default=None):
return self.request.session.get(name, default) if self.request else default
def session_set(self, name, value):
if self.request:
self.request.session[name] = value
def session_pop(self, name, default=None):
return self.request.session.pop(name, default) if self.request else defaultfrom flask import request, session, redirect as flask_redirect, g
from social_core.strategy import BaseStrategy
class FlaskStrategy(BaseStrategy):
"""Flask framework strategy implementation."""
def __init__(self, storage, tpl=None):
super().__init__(storage, tpl)
def get_setting(self, name):
from flask import current_app
return current_app.config.get(name)
def request_data(self, merge=True):
if merge:
data = request.args.to_dict()
data.update(request.form.to_dict())
return data
return request.args if request.method == 'GET' else request.form
def request_host(self):
return request.host
def redirect(self, url):
return flask_redirect(url)
def html(self, content):
from flask import Response
return Response(content, content_type='text/html')
def build_absolute_uri(self, path=None):
return request.url_root.rstrip('/') + (path or '')
def session_get(self, name, default=None):
return session.get(name, default)
def session_set(self, name, value):
session[name] = value
def session_pop(self, name, default=None):
return session.pop(name, default)from fastapi import Request
from fastapi.responses import RedirectResponse, HTMLResponse
from social_core.strategy import BaseStrategy
class FastAPIStrategy(BaseStrategy):
"""FastAPI framework strategy implementation."""
def __init__(self, storage, request: Request = None, tpl=None):
self.request = request
super().__init__(storage, tpl)
def get_setting(self, name):
# Implement settings retrieval for FastAPI
return getattr(settings, name, None)
def request_data(self, merge=True):
if not self.request:
return {}
# FastAPI request data handling
return dict(self.request.query_params)
def request_host(self):
return self.request.client.host if self.request else ''
def redirect(self, url):
return RedirectResponse(url=url)
def html(self, content):
return HTMLResponse(content=content)
def build_absolute_uri(self, path=None):
if not self.request:
return path
base_url = f"{self.request.url.scheme}://{self.request.url.netloc}"
return base_url + (path or '')
def session_get(self, name, default=None):
# Implement session handling for FastAPI
return getattr(self.request.session, 'get', lambda k, d: d)(name, default)
def session_set(self, name, value):
# Implement session handling for FastAPI
if hasattr(self.request, 'session'):
self.request.session[name] = value
def session_pop(self, name, default=None):
# Implement session handling for FastAPI
if hasattr(self.request, 'session'):
return self.request.session.pop(name, default)
return defaultThe strategy interface integrates with framework-specific configuration systems:
# Django settings.py
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = 'your-client-id'
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = 'your-client-secret'
SOCIAL_AUTH_LOGIN_REDIRECT_URL = '/'
SOCIAL_AUTH_PIPELINE = (
'social_core.pipeline.social_auth.social_details',
# ... additional pipeline steps
)
# Flask config
class Config:
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = 'your-client-id'
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = 'your-client-secret'
SOCIAL_AUTH_LOGIN_REDIRECT_URL = '/'
# FastAPI settings
from pydantic import BaseSettings
class Settings(BaseSettings):
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY: str
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET: str
SOCIAL_AUTH_LOGIN_REDIRECT_URL: str = '/'The strategy interface enables social-auth-core to maintain consistent behavior across different web frameworks while adapting to each framework's specific patterns for request handling, response generation, session management, and configuration.
Install with Tessl CLI
npx tessl i tessl/pypi-social-auth-core