Skip to content

Institutional Auth0 login fails to load API key (401 on /v1/profile); logout does not clear SSO session #34

@FarukZahiragic

Description

@FarukZahiragic

Summary

Users who sign in via Auth0 Institutions (enterprise/SSO) cannot retrieve their platform API key. The UI shows "Error loading API key" even though login appears successful. Direct email/password signup/login works correctly.

A secondary issue: after clicking Logout, signing in again on the same tab silently re-authenticates without prompting for credentials.

Environment

Steps to reproduce

Bug 1 — API key fails for institutional login

  1. Go to serving site and click Sign In
  2. On Auth0 Universal Login, use Institutions (enterprise/SSO connection)
  3. Complete login successfully
  4. Navigate to View API Key (/api_key)
  5. Observe "Error loading API key" banner

Expected: API key loads; account status shows Active (for allowed domains).

Actual: Frontend request to GET /v1/profile fails with HTTP 401:
{"status_code":401,"detail":"Invalid access token","headers":null}

Clearing browser storage/cookies and re-authenticating does not fix it.

Control case: Sign up directly on the platform with an EPFL email and log in with password → /v1/profile succeeds and API key loads.

Bug 2 — Logout does not require credentials on re-login

  1. Log in (any method)
  2. Click Logout
  3. Immediately click Sign In again on the same tab

Expected: User is prompted for credentials.

Actual: User is silently re-authenticated (Auth0 SSO session persists).

Root cause (investigation)

Both login paths use the same frontend SignIn provider="auth0" and hit the same backend endpoint GET /v1/profile.

The backend validates the session access token by calling Auth0 /userinfo, then looks up/creates an API key by user_profile["email"].

Problems identified in backend/routers/profile.py and backend/services/auth_service.py:

  1. Institutional SSO profiles often lack a top-level email claim — email may be under preferred_username, upn, or a namespaced SAML claim. Direct access to user_profile["email"] raises KeyError, which is caught by a broad except Exception and reported as a generic 401.
  2. return HTTPException(...) instead of raise — may produce a malformed response body matching the observed {"status_code":401,...} shape.
  3. Logout — SignOut only clears the local app session cookie; it does not clear localStorage (apiKey) or terminate the Auth0 SSO session via federated logout (/v2/logout).

This is not a database whitelist/initialization issue for typical Swiss institutional emails — it is primarily an identity claim mapping + error handling issue.

Proposed fix

Backend

  • Add robust email extraction from Auth0 userinfo (email, preferred_username, upn, SAML email claim) with normalization to lowercase
  • Use AUTH0_DOMAIN from settings for userinfo URL (instead of hardcoded domain)
  • Replace broad exception swallowing with distinct errors:
    • 401 — token rejected by Auth0
    • 422 — token valid but no email claim (log available claim keys)
    • 502 — upstream Auth0 failure
  • raise HTTPException instead of returning it

Frontend

  • Replace plain SignOut with logout that:
    • Clears localStorage (apiKey, accessToken)
    • Performs Auth0 federated logout via /v2/logout

Auth0 / deployment prerequisites (for logout fix)

  • Add app origins to Allowed Logout URLs in Auth0
  • Ensure VITE_AUTH0_DOMAIN and VITE_AUTH0_CLIENT_ID are set on frontend (same client ID as AUTH0_CLIENT_ID)

Acceptance criteria

  • Institutional/SSO login → /v1/profile returns 200 with api_key
  • Direct email/password login still works
  • Same user maps to same API key regardless of login method (email normalized)
  • Logout → Sign In prompts for credentials (no silent SSO re-auth)
  • localStorage.apiKey cleared on logout
  • Backend logs distinguish token rejection vs missing email claim

Testing plan (before merge)

  1. Open PR — CI lint/tests pass
  2. Local backend test with real institutional Auth0 token:
    curl -H "Authorization: Bearer $TOKEN" http://localhost:8080/v1/profile
  3. Compare Auth0 userinfo payload for institutional vs database connection users
  4. After merge to main (auto-deploy dev): smoke test on servingdev — Institutions login, API key page, logout flow

Notes

  • Frontend route is /api_key; backend endpoint is GET /v1/profile (not /api_key)
  • If fix returns 422 instead of 401, Auth0 attribute mapping for that connection may need updating

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions