OAuth2 providers pack (Google, GitHub, Microsoft, Apple, Discord, Facebook, GitLab, LinkedIn, Twitch) for the Asok framework.
Project description
asok-auth-providers
OAuth2 Providers pack for the Asok Framework.
Ships ready-to-use Google, GitHub, Microsoft, Apple, Discord, Facebook, GitLab, LinkedIn, and Twitch sign-in flows, templates, and style sheets.
Resources
- PyPI Project: pypi.org/project/asok-auth-providers
- Asok Framework: asok-framework.com
- Asok Repository: github.com/asok-framework/asok
- Extension Repository: github.com/codewithmpia/asok-auth-providers
Installation
pip install asok-auth-providers
Quick start
# wsgi.py
from asok import Asok
from asok_auth_providers import AsokAuthProvidersExtension
app = Asok()
app.config["OAUTH_PROVIDERS"] = {
"google": {
"client_id": "...",
"client_secret": "...",
"label": "Google Workspace"
},
...
}
def on_oauth_login(request, user_info):
"""Find or create a local user, then call request.login(user)."""
from src.models.user import User
user = User.find(email=user_info["email"]) or User.query().create(
email=user_info["email"],
name=user_info["name"],
)
request.login(user)
app.register_extension(AsokAuthProvidersExtension(
app,
on_login=on_oauth_login,
login_redirect="/dashboard",
login_failed_redirect="/login",
compact=True,
label_format="Connecter avec {}",
))
Extension Anatomy
When you register AsokAuthProvidersExtension with your Asok app, it registers and manages the following components:
1. Routes & Page Handlers
The extension dynamically registers the following directory-based routes using the dynamic parameter [provider] folder:
GET /auth/<provider>/login: Redirects the user to the provider's authorization consent screen.GET /auth/<provider>/callback: Receives the callback, validates security state keys, performs backend token exchanges, retrieves user profiles, executes your customon_logincallback, and redirects the user.
2. Template Helpers & Globals
The extension exposes the following context helper variables and callable functions to all templates:
oauth_providers: The dictionary of brand names and default capitalized labels.oauth_icon(provider): Outputs the inline SVG logo element for the selected provider.oauth_login_url(provider, next_url): Generates the routing login URLs (e.g.,/auth/google/login?next=/dashboard).oauth_providers_css(): Emits the standard<link>stylesheet element for the buttons.oauth_compact&oauth_label_format: The default layout preferences configured on your Python extension registry.
3. Static Assets
/css/oauth-buttons.css: The stylesheet specifying sizes, hover scaling transitions, active states, flex grids, and brand background colors.
Sign-in buttons
The template renders the button elements directly without a wrapper div. This allows complete freedom to wrap and style the layout however you want (for example, wrapping them in a flex container using Tailwind CSS or custom styles):
<div class="flex flex-wrap gap-2">
{% include "auth_providers/buttons.html" %}
</div>
To customize the provider list, set providers before the include:
{% set providers = ["google", "github"] %}
{% include "auth_providers/buttons.html" %}
To customize the button labels, set a labels dictionary before the include (which maps provider names to custom strings), or provide a label_format template string (where {} is replaced by the provider's label):
{% set labels = {"google": "Google Workspace"} %}
{% set label_format = "Connecter avec {}" %}
{% include "auth_providers/buttons.html" %}
To render compact buttons (only showing the brand icons without text):
{% set compact = true %}
{% include "auth_providers/buttons.html" %}
To pass custom CSS classes directly to the elements (perfect for Tailwind CSS layouts):
{# Completely override the default button classes #}
{% set button_class = "flex items-center rounded-lg px-4 py-2 text-white font-medium" %}
{# Or append extra classes to the default layout styles #}
{% set extra_class = "shadow hover:shadow-md transition-shadow" %}
{# Append classes to the inner label text span (e.g. for responsive hiding) #}
{% set label_class = "hidden md:inline-block ml-2" %}
{% include "auth_providers/buttons.html" %}
To preserve a post-login redirect:
{% set next_url = "/dashboard" %}
{% include "auth_providers/buttons.html" %}
Include the default CSS:
<link rel="stylesheet" href="/css/oauth-buttons.min.css">
Configuration
Set app.config["OAUTH_PROVIDERS"] to a dict mapping provider names to {client_id, client_secret} credentials.
To avoid hardcoding sensitive credentials in your codebase, it is highly recommended to load them from environment variables (defined in your .env file).
Example .env file
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret
Loading in wsgi.py
import os
app.config["OAUTH_PROVIDERS"] = {
"google": {
"client_id": os.environ.get("GOOGLE_CLIENT_ID"),
"client_secret": os.environ.get("GOOGLE_CLIENT_SECRET"),
"label": "Google Workspace"
},
"github": {
"client_id": os.environ.get("GITHUB_CLIENT_ID"),
"client_secret": os.environ.get("GITHUB_CLIENT_SECRET"),
},
}
Only providers explicitly present in the dict are enabled — the extension will never auto-enable a provider without credentials.
[!IMPORTANT] Understanding
client_idandclient_secretThese are not your personal user credentials (like your email address, username, login password, or SMTP app-specific passwords).
Instead, they are the OAuth2 Application Credentials generated by registering a web application on each provider's developer portal:
- Google: Register on the Google Cloud Console (APIs & Services > Credentials)
- GitHub: Register a new OAuth App on GitHub Developer Settings
- Microsoft: Register under App Registrations in the Microsoft Entra ID Portal
- Apple: Configure a Service ID on the Apple Developer Account (Certificates, Identifiers & Profiles)
- Discord: Create an application on the Discord Developer Portal
- Facebook: Register an App on the Meta for Developers portal
- GitLab: Add an application in GitLab User Applications Settings
- LinkedIn: Register on the LinkedIn Developer Portal
- Twitch: Register your application in the Twitch Developer Console
During registration on those developer portals, you must configure the Redirect URI / Callback URL to point to your application callback URL:
https://<your-domain>/auth/<provider>/callback(orhttp://127.0.0.1:8000/auth/github/callbackduring local development).
Customizing Labels and Layout Defaults
You can configure default layout parameters directly when initializing AsokAuthProvidersExtension in your Python code:
compact(bool): IfTrue, renders only the brand logo icons without text by default. (Default:False)label_format(str): A format pattern string (e.g.,"Connecter avec {}") to format button text by default. (Default:"")
For example:
app.register_extension(AsokAuthProvidersExtension(
app,
on_login=on_oauth_login,
compact=True,
label_format="Se connecter avec {}"
))
Additionally, you can specify custom labels for individual providers directly in app.config["OAUTH_PROVIDERS"] using the label key:
app.config["OAUTH_PROVIDERS"] = {
"google": {
"client_id": "...",
"client_secret": "...",
"label": "Google Workspace" # Will render as: "Se connecter avec Google Workspace"
}
}
You can also set APP_URL to lock the callback host (recommended in
production to prevent host-header tampering):
app.config["APP_URL"] = "https://app.example.com"
Otherwise the callback URL is reconstructed from the current request's
scheme and Host header.
Supported providers
| Provider | Notes |
|---|---|
Already in asok.auth.OAuth core, re-exposed here. |
|
| github | Already in asok.auth.OAuth core, re-exposed here. |
| microsoft | Common (multi-tenant) authority endpoint. |
| apple | id_token JWT decode (no userinfo endpoint). |
| discord | Requires identify email scopes. |
Requires email public_profile scopes. |
|
| gitlab | Hosted gitlab.com only; self-hosted needs a custom config. |
| OpenID Connect userinfo endpoint. | |
| twitch | Requires user:read:email scope. |
Security notes
- The OAuth
stateparameter is generated withsecrets.token_urlsafe(32)and stored in the session. It is popped during the callback, so a callback URL cannot be replayed. - Apple's
id_tokenis JWT-decoded for claim extraction; signature verification against Apple's JWKS should be layered on top in production. APP_URLis honored when present, so the callback URL is not subject toHostheader tampering.
Hooks
AsokAuthProvidersExtension(on_login=...) takes a callback (request, user_info) -> None that is executed when the OAuth provider returns user profile information successfully.
The user_info Structure
The user_info argument is a normalized dictionary:
{
"provider": "google",
"provider_id": "1234567890",
"email": "user@example.com",
"name": "User Name",
"picture": "https://...", # URL to their profile avatar
"raw": {...}, # The raw, unfiltered provider response
}
Implementing on_login
In your login hook, you can query your database to find or create the user, update their profile metadata (such as their name or picture URL), and log them into the Asok session:
def on_oauth_login(request, user_info):
from src.models.user import User
# Find an existing user by email
user = User.find(email=user_info["email"])
if not user:
# Create a new user account if they don't exist
user = User.create(
email=user_info["email"],
name=user_info["name"],
picture=user_info["picture"],
oauth_provider=user_info["provider"],
oauth_id=user_info["provider_id"]
)
else:
# Update existing user profile assets (e.g. name or avatar URL)
user.update(
name=user_info["name"] or user.name,
picture=user_info["picture"] or user.picture,
oauth_provider=user_info["provider"],
oauth_id=user_info["provider_id"]
)
# Log the user into the Asok session
request.login(user)
Once request.login(user) is called, the logged-in user becomes globally accessible in all your templates and controllers via the request.user property:
<!-- Inside any page template -->
<div class="profile-card">
{% if request.user.picture %}
<img src="{{ request.user.picture }}" alt="{{ request.user.name }}">
{% endif %}
<h2>Welcome back, {{ request.user.name }}!</h2>
<p>Logged in via {{ request.user.oauth_provider | capitalize }}</p>
</div>
If no on_login callback is provided, the normalized user_info dict is stashed in request.session["oauth_user_info"], and the user is redirected to login_redirect.
License
This project is licensed under the MIT License. See the LICENSE file for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file asok_auth_providers-1.0.0.tar.gz.
File metadata
- Download URL: asok_auth_providers-1.0.0.tar.gz
- Upload date:
- Size: 25.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
67a077cb19e1bfec9f69d459093fe6246244d8f113df6908a662bcc7a998141c
|
|
| MD5 |
0c75d069e3d9e553e89b9b4c4a992cb0
|
|
| BLAKE2b-256 |
698396d740beb8e351fb8b532813dc0bc453be6b6d1b6bf683fa82d942e3cf09
|
Provenance
The following attestation bundles were made for asok_auth_providers-1.0.0.tar.gz:
Publisher:
release.yml on codewithmpia/asok-auth-providers
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
asok_auth_providers-1.0.0.tar.gz -
Subject digest:
67a077cb19e1bfec9f69d459093fe6246244d8f113df6908a662bcc7a998141c - Sigstore transparency entry: 1917074570
- Sigstore integration time:
-
Permalink:
codewithmpia/asok-auth-providers@1b84b235061613b31257577d72a4e2dfe82e6989 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/codewithmpia
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@1b84b235061613b31257577d72a4e2dfe82e6989 -
Trigger Event:
release
-
Statement type:
File details
Details for the file asok_auth_providers-1.0.0-py3-none-any.whl.
File metadata
- Download URL: asok_auth_providers-1.0.0-py3-none-any.whl
- Upload date:
- Size: 22.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
328f9e216b2cecc4c63862ff639b9fe3a49643b3705e01a559ffcd8d0b1fbb48
|
|
| MD5 |
193461ae2bc9a42c05fb01f68fd00f73
|
|
| BLAKE2b-256 |
4f43e7a1c052eeb1ff5d5f9f44471d297b8067e8971c44501dd8170261b70b2e
|
Provenance
The following attestation bundles were made for asok_auth_providers-1.0.0-py3-none-any.whl:
Publisher:
release.yml on codewithmpia/asok-auth-providers
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
asok_auth_providers-1.0.0-py3-none-any.whl -
Subject digest:
328f9e216b2cecc4c63862ff639b9fe3a49643b3705e01a559ffcd8d0b1fbb48 - Sigstore transparency entry: 1917074645
- Sigstore integration time:
-
Permalink:
codewithmpia/asok-auth-providers@1b84b235061613b31257577d72a4e2dfe82e6989 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/codewithmpia
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@1b84b235061613b31257577d72a4e2dfe82e6989 -
Trigger Event:
release
-
Statement type: