Skip to content

feat(auth): accept "Sign in with µLearn" tokens, auth admin console, authserver-owned passwords - #3251

Merged
DevWithPranav merged 9 commits into
gtech-mulearn:devfrom
DevWithPranav:feat/new-auth
Oct 17, 2026
Merged

DevWithPranav merged 9 commits into
gtech-mulearn:devfrom
DevWithPranav:feat/new-auth

Conversation

@DevWithPranav

Copy link
Copy Markdown
Collaborator

What this does

Lets the backend accept the new "Sign in with µLearn" tokens from authserver (RS256 JWTs, checked locally against authserver's public keys), alongside the old login tokens. Current users and the current dashboard keep working unchanged.

It also adds the admin console for the new login, moves password changes to authserver, and gives authserver a protected API to create members at signup.

Pairs with authserver feat/new-auth. Deploy both together.

Main changes

Token checking (utils/token_verification.py, utils/permission.py)

  • Accepts both: old HS256 tokens and new RS256 tokens.
  • New tokens are checked against authserver's JWKS (cached; fetched again on an unknown kid, so key rotation needs no restart), plus iss, aud (mulearn-api) and exp.
  • Scopes: mulearn.read for reads, mulearn.write for changes. Partner tokens (no mulearn.* scope) are refused.
  • Roles for new tokens come from the database on every request, so role changes apply immediately.
  • Each request logs which token kind was used (auth_migration.log: legacy_hs256 / oidc_rs256), so we can see when the old login is no longer used.
  • Keeps working when authserver is down (cached keys).

Protected identity API for authserver (/api/v1/protected/identity/provision-member/, needs PROTECTED_API_KEY)

  • Creates the member (user, muid, wallet, role) when someone signs up on the new login site, and sends the same welcome email as the old signup.

User info (/api/v1/dashboard/user/info/)

  • New onboarding field: {"state": "COMPLETE" | "INCOMPLETE", "missing": [...], "exempt": bool}, so the dashboard knows when to send new users to onboarding.

Password change (/api/v1/dashboard/profile/change-password/)

  • Now handled by authserver: it checks the current password, applies the password rules, saves the hash and logs the user out everywhere. The backend no longer writes user.password here. Returns 503 if authserver is down.

Auth admin console (/api/v1/dashboard/auth-admin/, admins only)

  • Login attempts, security settings, sign-in policy, OAuth apps (list, create, edit, disable, enable), and revoke a user's sessions.
  • Every change is written to the audit log with new AUTH_* action types.

Hourly token cleanup (mu_celery/auth_token_cleanup_cron.py)

  • Celery beat calls authserver at minute 50 each hour to delete expired tokens (capped per call, with a lock so two runs don't overlap).

Old signup (kept for now)

  • RegisterDataAPI still works, and now logs a counter (mulearn.legacy_signup) so we know when it's safe to remove.
  • Throttles added: registration 10/hour, email check 20/min.

Other

  • db/user.py: declares the existing deleted_at / deleted_by columns (not enforced).
  • scripts/check_schema_drift.py (with tests) and a CI workflow.
  • Merged latest dev. The only conflict was mulearnbackend/celery.py, and both Celery jobs are kept.

Also in this branch (from feat/sign-in-with-mulearn, not auth-related): achievement_views.py wraps achievement creation and template generation in try/except. Reviewers: note that it returns str(e) to the client.

Testing

  • Unit tests: 62 passed (token verification, onboarding, schema drift).
  • Full local end-to-end test with authserver, the new login site and the dashboard: 250 checks, 235 pass, 13 notes, 2 fails.
  • Covered:
    • old and new tokens together;
    • wrong issuer, audience or signature;
    • forged, edited and partner tokens;
    • read-only scope;
    • admin console and audit rows;
    • password change, including with authserver down;
    • onboarding;
    • token cleanup;
    • key rotation with no restart.
  • Known issues (not blocking):
    • A name with emoji fails at signup: the MySQL connection needs utf8mb4 (the old signup has the same bug).
    • Double-clicking signup can return a 500 instead of "already exists". Only one account is created.
    • The backend returns 403 (not 401) for bad tokens.
  • pytest on the whole repo shows 4 collection errors in learningcircle, mentor and projects tests. These already happen on dev (several folders are named tests) and aren't caused by this PR.

awindsr and others added 5 commits August 25, 2026 14:42
- Introduced onboarding completeness logic in `utils/onboarding.py` to determine if a user has completed onboarding based on roles and domain count.
- Implemented session revocation mechanism in `utils/session_revocation.py` to invalidate sessions upon credential changes, addressing audit finding F3.
- Added comprehensive tests for onboarding logic in `utils/test_onboarding.py` to ensure correct behavior across various scenarios.
- Created tests for token verification in `utils/test_token_verification.py`, covering both legacy HS256 and new RS256 formats.
- Developed token verification logic in `utils/token_verification.py` to handle dual-format tokens, ensuring secure validation and normalization of claims.
…with OAuth client management and session revocation
@greptile-apps

greptile-apps Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

The PR appears safe to merge based on this review; the previously reported sweep starvation is addressed and no new blocking issue was confirmed.

Findings

  1. P1 Security Pending revocations can starve ▶

Summary

The PR adds dual-format token verification, authserver-backed member and password workflows, an auth admin console, onboarding status, and scheduled token and session cleanup. The latest change replaces the pending-revocation hash sweep with a sorted-set queue so failed members move behind those awaiting an attempt.

Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Reset[Password reset] --> Pending[Pending revocation queue]
  Pending --> Fast[Immediate retry task]
  Pending --> Sweep[15-minute sweep]
  Fast --> Auth[Authserver session revocation]
  Sweep --> Auth
  Auth -->|Confirmed| Clear[Remove pending record]
  Auth -->|Incomplete| Pending
Loading

Reviews (5) · Last reviewed commit: "feat(auth): update session revocation lo..."

Comment thread utils/permission.py
Comment thread .github/workflows/ci.yml Outdated
Comment thread api/protected/identity/views.py Outdated
Comment thread api/protected/identity/views.py Outdated
Comment thread api/dashboard/user/dash_user_views.py
Comment thread utils/token_verification.py Outdated
Comment thread api/dashboard/achievement/achievement_views.py Outdated
Comment thread .github/workflows/ci.yml Outdated
Comment thread api/dashboard/auth_admin/auth_admin_views.py
- Enhanced ProvisionMemberAPI to handle concurrent signups by wrapping user creation in a transaction, ensuring atomicity and preventing half-provisioned members.
- Removed the check_schema_drift.py script and its associated tests, as well as the conftest.py file, streamlining the project structure.
- Updated requirements-dev.txt to explicitly include PyJWT and cryptography versions for token verification.
- Added JWTUtils.is_logged_in method to check if a request carries a valid token, improving permission handling.
- Improved _JWKSCache to manage key fetching and caching more effectively, ensuring that tokens remain verifiable during authserver outages.
- Added comprehensive tests for the new JWKS cache behavior, ensuring robustness against key rotation and authserver unavailability.
Comment thread utils/token_verification.py
Comment thread api/dashboard/user/dash_user_views.py
Comment thread mu_celery/auth_session_tasks.py
Comment thread mu_celery/auth_session_tasks.py Outdated
@DevWithPranav
DevWithPranav merged commit 69b929a into gtech-mulearn:dev Oct 17, 2026
2 checks passed
@github-project-automation github-project-automation Bot moved this from In Review to QA in µLearn Delivery Oct 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: QA

Development

Successfully merging this pull request may close these issues.

2 participants