Feat: OIDC UI bridge, Microsoft SSO,, and schema session flaws

- OAuth Callback to Use Gatehouse UI to login instead of Backend Served dull ui
- Setup Autoregister of user + org, on oauth
- Microsoft Oauth Support
- OIDCRefreshToken.access_token_id  had a narrow Column increased to VAR(255) and remove FK to sessions.id which had no use
- client_id and client.id mismatch ,backup-code consumption
This commit is contained in:
2026-02-26 23:18:31 +05:45
parent f1fff22f3e
commit 1ba5738d52
14 changed files with 732 additions and 349 deletions
+69 -7
View File
@@ -12,6 +12,12 @@ Usage:
--client-secret "YOUR_CLIENT_SECRET" \\
--redirect-url "http://localhost:5173/auth/callback"
# Create a Microsoft provider configuration
python scripts/configure_oauth_provider.py create microsoft \\
--client-id "YOUR_AZURE_APP_ID" \\
--client-secret "YOUR_AZURE_CLIENT_SECRET" \\
--redirect-url "http://localhost:5000/api/v1/auth/external/microsoft/callback"
# List all configured providers
python scripts/configure_oauth_provider.py list
@@ -27,6 +33,11 @@ Usage:
# Use environment variables
GOOGLE_CLIENT_ID=xxx GOOGLE_CLIENT_SECRET=yyy \\
python scripts/configure_oauth_provider.py create google
# Use environment variables (Microsoft)
MICROSOFT_CLIENT_ID=xxx MICROSOFT_CLIENT_SECRET=yyy \\
python scripts/configure_oauth_provider.py create microsoft
"""
import os
@@ -50,6 +61,33 @@ from gatehouse_app import create_app
from gatehouse_app.services.external_auth_service import ExternalAuthService, ExternalAuthError
def _microsoft_defaults() -> dict:
"""
Build Microsoft provider defaults, honouring MICROSOFT_TENANT_ID if set.
Tenant options:
- "common" : work/school AND personal Microsoft accounts (app must be
registered with "Accounts in any organizational directory
and personal Microsoft accounts" in Azure Portal)
- "consumers" : personal Microsoft accounts only (MSA)
- "organizations": work/school accounts only (AAD)
- "<tenant-id>": single specific Azure AD tenant (most secure for enterprise)
Set MICROSOFT_TENANT_ID env var or pass --tenant-id to the script.
"""
tenant = os.environ.get("MICROSOFT_TENANT_ID", "common")
base = f"https://login.microsoftonline.com/{tenant}"
return {
"auth_url": f"{base}/oauth2/v2.0/authorize",
"token_url": f"{base}/oauth2/v2.0/token",
"userinfo_url": "https://graph.microsoft.com/oidc/userinfo",
"jwks_url": f"{base}/discovery/v2.0/keys",
# offline_access is required by Microsoft to receive a refresh token
# (unlike Google which uses access_type=offline as a query param)
"scopes": ["openid", "profile", "email", "offline_access"],
}
# Provider endpoint configurations
PROVIDER_DEFAULTS = {
"google": {
@@ -65,13 +103,7 @@ PROVIDER_DEFAULTS = {
"userinfo_url": "https://api.github.com/user",
"scopes": ["read:user", "user:email"],
},
"microsoft": {
"auth_url": "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
"token_url": "https://login.microsoftonline.com/common/oauth2/v2.0/token",
"userinfo_url": "https://graph.microsoft.com/oidc/userinfo",
"jwks_url": "https://login.microsoftonline.com/common/discovery/v2.0/keys",
"scopes": ["openid", "profile", "email"],
},
"microsoft": _microsoft_defaults(),
}
@@ -163,6 +195,25 @@ def create_provider(args):
return 1
defaults = PROVIDER_DEFAULTS[provider_type]
# For Microsoft, allow --tenant-id / MICROSOFT_TENANT_ID to override URLs at create time
if provider_type == "microsoft":
tenant_id = getattr(args, "tenant_id", None) or os.environ.get("MICROSOFT_TENANT_ID")
if tenant_id and tenant_id != os.environ.get("MICROSOFT_TENANT_ID", "common"):
# Recompute URLs with the supplied tenant
os.environ["MICROSOFT_TENANT_ID"] = tenant_id
defaults = _microsoft_defaults()
print_info(f"Using Microsoft tenant: {tenant_id}")
elif tenant_id:
print_info(f"Using Microsoft tenant: {tenant_id}")
else:
print_warning(
"No --tenant-id provided; using 'common'.\n"
" • For personal Microsoft accounts: your Azure app must be registered with\n"
" 'Accounts in any organizational directory and personal Microsoft accounts'.\n"
" • For work/school only: use --tenant-id organizations\n"
" • For a single Azure AD tenant: use --tenant-id <your-tenant-id>"
)
# Build configuration
config_data = {
@@ -231,6 +282,9 @@ def update_provider(args):
if args.enabled is not None:
updates["is_enabled"] = args.enabled
if args.scopes:
updates["scopes"] = [s.strip() for s in args.scopes.split(",")]
if args.settings:
settings = {}
for setting in args.settings:
@@ -443,6 +497,13 @@ Supported Providers:
create_parser.add_argument("--redirect-url", help="Default redirect URL for OAuth callbacks")
create_parser.add_argument("--disabled", action="store_true", help="Create provider in disabled state")
create_parser.add_argument("--settings", action="append", help="Custom settings (key=value format)")
create_parser.add_argument(
"--tenant-id",
help=(
"Microsoft only: Azure AD tenant ID (or 'common' / 'consumers' / 'organizations'). "
"Defaults to the MICROSOFT_TENANT_ID env var, then 'common'."
),
)
create_parser.set_defaults(func=create_provider)
# Update command
@@ -453,6 +514,7 @@ Supported Providers:
update_parser.add_argument("--redirect-url", help="New default redirect URL")
update_parser.add_argument("--enabled", type=lambda x: x.lower() in ['true', '1', 'yes'],
help="Enable or disable the provider (true/false)")
update_parser.add_argument("--scopes", help="Comma-separated list of OAuth scopes to set (e.g. 'openid,profile,email,offline_access')")
update_parser.add_argument("--settings", action="append", help="Custom settings to update (key=value format)")
update_parser.set_defaults(func=update_provider)