mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-05-09 08:25:54 +02:00
[PR #1103] [MERGED] feat(oidc): Azure Entra ID support — configurable email claim & verification + Remember Me persistent login #1164
Labels
No labels
A1
automated
automated
bug
bug
Closed due to inactivity
contrib
dependencies
dependencies
duplicate
enhancement
feedback
hold
invalid
Notes
P1S
pull-request
security
ThumbsUp
user-report
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/bambuddy-maziggy-1#1164
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/maziggy/bambuddy/pull/1103
Author: @netscout2001
Created: 4/23/2026
Status: ✅ Merged
Merged: 4/24/2026
Merged by: @maziggy
Base:
dev← Head:feature/2fa-oidc-authentication📝 Commits (9)
4e54fb1feat(oidc): add Azure Entra ID support with configurable email claim resolution904c83efix(oidc): harden email claim resolution, guards, and test coveragea9ec562fix(oidc): apply maintainer review fixes for Azure Entra ID support144b932feat(auth): add Remember Me option to login page3eb68fcfix(db): swallow 'no such column' in _safe_execute for idempotent RENAME COLUMN migrationsf22cd0ffix(oidc): harden _safe_execute, extract email/autolink helpers, add test coverage029be23fix(db): restore 'no such column' and 'duplicate column name' to _safe_execute swallow list6fdee8fMerge branch 'dev' into feature/2fa-oidc-authenticationf0483d8fix(oidc): polish Remember-Me persistence + email_claim UX + shape regex tests📊 Changes
25 files changed (+2494 additions, -514 deletions)
View changed files
📝
backend/app/api/routes/mfa.py(+118 -18)📝
backend/app/core/database.py(+76 -10)📝
backend/app/models/oidc_provider.py(+24 -1)📝
backend/app/schemas/auth.py(+56 -3)📝
backend/tests/integration/test_mfa_api.py(+768 -0)📝
backend/tests/unit/test_db_dialect.py(+143 -4)📝
backend/tests/unit/test_mfa_helpers.py(+45 -1)➕
docs/authentication/entra-id.md(+82 -0)📝
frontend/src/__tests__/api/client.test.ts(+46 -0)➕
frontend/src/__tests__/components/OIDCProviderSettings.test.tsx(+151 -0)📝
frontend/src/__tests__/pages/LoginPage.test.tsx(+328 -1)📝
frontend/src/api/client.ts(+26 -12)📝
frontend/src/components/OIDCProviderSettings.tsx(+51 -1)📝
frontend/src/contexts/AuthContext.tsx(+9 -9)📝
frontend/src/i18n/locales/de.ts(+8 -0)📝
frontend/src/i18n/locales/en.ts(+8 -0)📝
frontend/src/i18n/locales/fr.ts(+8 -0)📝
frontend/src/i18n/locales/it.ts(+8 -0)📝
frontend/src/i18n/locales/ja.ts(+8 -0)📝
frontend/src/i18n/locales/pt-BR.ts(+8 -0)...and 5 more files
📄 Description
Description
This PR combines two improvements to the OIDC / authentication flow:
1 — Azure Entra ID support + hardening (maintainer review fixes)
Adds Azure Entra ID support to the OIDC provider configuration by introducing two new fields:
email_claimandrequire_email_verified.Azure Entra ID never includes the
email_verifiedclaim in its ID tokens. The previous code dropped the email wheneveremail_verifiedwas absent (fail-closed), breaking Azure logins. This PR introduces three configurable email resolution paths:email_claim="email"+require_email_verified=true— standard behaviour, unchangedemail_claim="email"+require_email_verified=false— permissive mode, accepts email whenemail_verifiedis absentemail_claim != "email"— custom claim (preferred_username,upn), noemail_verifiedcheck; recommended for Azure Entra IDauto_link_existing_accountsis blocked at schema level, route level, and DB level when either new field would make auto-linking unsafe (SEC-1/SEC-6).This PR also addresses the subsequent maintainer review feedback:
_EMAIL_SHAPE_REis now precompiled at module level and usesfullmatch()with a stricter pattern that requires a dot in the domain (local@domain.tld) — rejectsx@nodot,@domain,x@, etc.provider_id,email_claimname, andsubare emitted.= 0/= 1to= FALSE/= TRUEso the constraint compiles correctly on PostgreSQL._safe_executere-raises on real errors: Non-idempotency errors are now logged withlogger.errorand re-raised so a failed migration aborts startup loudly instead of silently continuing.provider_emaillowercasing migration: Normalises existing mixed-case UPN values (common with Azure Entra ID) to lowercase for consistent matching.docs/authentication/entra-id.mdcovering app registration, client secret, issuer URL, BamBuddy provider config,preferred_usernamevsemailclaim, and a troubleshooting table._safe_executereraise/swallow behaviour,provider_emaillowercasing migration, andFALSE/TRUECheckConstraint enforcement.2 — Remember Me persistent login
sessionStorageandlocalStorage, so the session survives a tab close / browser restart.TokenPersistence = 'session' | 'persistent'type, replacing the previouspersist?: booleanparameter throughoutclient.ts,AuthContext, andLoginPage.sessionStorageasauth_remember_me=1before the provider redirect and consumed (read + removed atomically) in the OIDC callbackuseEffect, so the setting carries through the external redirect where React state is lost.try-catchwithconsole.warnto handle private browsing / quota errors gracefully (in-memory token still works for the current tab).rememberMei18n key added to all 8 locale files (en, de, fr, it, pt-BR, zh-CN, ja, zh-TW).client.test.ts; Remember Me checkbox, session/persistent storage, OIDC carry-through, OIDC+2FA carry-through, error cleanup, and negative cases inLoginPage.test.tsx.Related Issues
Fixes #902 #1088
Documentation
https://github.com/maziggy/bambuddy-wiki/pull/19
Type of Change
Changes Made
Backend
backend/app/api/routes/mfa.py— precompiled_EMAIL_SHAPE_RE, PII-free log, three-case email resolution (Case A/B/C),_is_valid_email_shapedhelper, Combined-State-Guard in PUT handlerbackend/app/models/oidc_provider.py—email_claimandrequire_email_verifiedORM fields,CheckConstraintusesFALSE/TRUEbackend/app/core/database.py— column migrations for new fields, PostgreSQLADD CONSTRAINTmigration,_safe_executelogs + re-raises non-idempotency errors,provider_emaillowercasing migrationbackend/app/schemas/auth.py— new fields onOIDCProviderCreate/OIDCProviderUpdate/OIDCProviderResponse,model_validatorfor SEC-1/SEC-6 on create and updatebackend/tests/integration/test_mfa_api.py— 19 new tests: 13-case parametrized matrix (Case A/B/C), SEC-1/SEC-6 guard tests, Combined-State-Guard tests, response field coverage,no-dot-in-domainmatrix casebackend/tests/unit/test_db_dialect.py— real SQLite integration tests for_safe_executeand migrationsdocs/authentication/entra-id.md— new Azure Entra ID setup guideFrontend
frontend/src/api/client.ts—TokenPersistencetype, updatedsetAuthTokensignature with try-catch, new fields onOIDCProviderandOIDCProviderCreateinterfacesfrontend/src/contexts/AuthContext.tsx—login/loginWithTokenacceptTokenPersistencefrontend/src/pages/LoginPage.tsx— Remember Me checkbox,consumeSavedRememberMe(),toPersistence()helper, OIDC sessionStorage flagfrontend/src/components/OIDCProviderSettings.tsx— toggle forrequire_email_verified, input foremail_claim, both shown in provider info viewfrontend/src/i18n/locales/*.ts—rememberMekey + OIDC settings keys in all 8 locale filesfrontend/src/__tests__/api/client.test.ts— 3 new persistence mode testsfrontend/src/__tests__/pages/LoginPage.test.tsx— 9 new Remember Me / OIDC carry-through testsScreenshots
Testing
117 backend integration tests pass (
pytest tests/integration/test_mfa_api.py). 1407 frontend tests pass (vitest run). No ruff or TypeScript warnings.Checklist
Additional Notes
Existing OIDC providers and login flows are fully backwards-compatible. Both new features are opt-in by default:
require_email_verified=true/email_claim='email'preserves the previous behaviour; the Remember Me checkbox defaults to unchecked.🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.