My Account API — Factor Management
Auth0's real self-service /me/v1/API, driven by Auth0's own official @auth0/universal-components-react components
Session (openid profile email)
Login carries no My Account scopes
Per call
getAccessToken({ audience, scope })
Requested per-operation, not at login
/me/v1/authentication-methods
read / create / update / delete, each its own scope
Unlike the Management API's single broad update:users-style scope, every My Account operation has its own narrow scope. This demo requests only the one scope each action needs, exactly when it needs it — not a bundle of permissions up front at login.
Sign in with any account — this demo manages whatever authentication methods exist for whoever logs in. A dedicated test account is available if you'd rather not use a personal one:
- my-account-api-demo@atko.email
Strengths
- Scopes are granular per operation — read:me:authentication_methods, create:/update:/delete:me:authentication_methods are each separate, unlike the Management API's broad update:users covering a whole user record. A token minted for listing factors cannot delete one.
- This demo requests each scope only at the moment the operation needs it, rather than bundling every My Account scope into the login-time authorization request — the session itself carries no more privilege than plain openid profile email.
- The real /me/v1/ API is purpose-built for self-service: it has no path to another user's data at all, unlike the Management API route this demo sits alongside, where the only thing preventing cross-user access is which :id the calling code happens to put in the URL.
- Factor enrollment/deletion UI here is Auth0's own official component (@auth0/universal-components-react's UserMFAManagement), not hand-rolled WebAuthn/OTP forms — the challenge/verify protocol details, QR rendering, and recovery-code UX are maintained by Auth0, not re-implemented and re-audited per demo or per app.
Risks & Considerations
- This tenant has an Early Access "Default Policy" on the /me/ resource server that step-ups MFA-enrolled users more than 15 minutes after login — confirmed live (an mfa_required response with a real mfa_token had to be completed via the verify-with-OTP grant before any call succeeded). A raw refresh_token grant exchange (what this demo uses, see below) cannot satisfy that challenge at all — it fails with unmet_authentication_requirements, "cannot be challenged" — so this policy had to be disabled tenant-wide for this demo's automated proxy flow to work for an already-enrolled account. A real app fronting this API behind a non-interactive proxy needs to design around this explicitly, not assume a background token refresh can always step up a user the way an interactive /authorize redirect can.
- The real /me/v1/profile endpoint has no working self-service scope on this tenant at all, in either direction — GET returns 403 Insufficient Scope and PATCH returns 404. No SDK (@auth0/myaccount-js has no profile client), no documentation, and a direct Management API scope audit of this resource server all agree: there is no real scope that grants access to it today. This demo originally assumed GET-only would work by analogy with authentication-methods; it does not.
- Deleting a user's only remaining authentication method (if password is also removed) could lock them out entirely — this API doesn't enforce "leave at least one factor" on your behalf.
- Getting a working access token for this audience required three separate pieces of tenant configuration beyond the resource server itself: a subject_type: "user" client grant (not "client"), an MRRT refresh_token.policies entry, and explicit per-scope "User-delegated Access" grants in the dashboard's API Access screen. Missing any one of the three produces a different, non-obvious error (a malformed-token error, a "not authorized" error, or an "insufficient scope" error respectively) rather than one consistent "not configured" message — easy to misdiagnose as an application bug.
Hardening Checklist
- Don't assume MFA step-up requirements away just because a first research pass (SDK docs, scope lists) didn't mention one — this tenant's actual behavior only surfaced through a live, interactive test with an MFA-enrolled account. Test the exact user state you expect in production, not just a configuration-matched test account.
- Short-lived access tokens for the /me/ audience limit the exposure window if one leaks.
- Log authentication-method create/delete events app-side; the API itself returns no notification to the user when a factor changes, unlike some IdPs that email on security-relevant account changes.
- Prefer Auth0's official components over hand-rolled equivalents for anything touching WebAuthn ceremonies or OTP verification flows — the protocol surface area is easy to get subtly wrong, and Auth0 maintains the component against its own API's actual behavior.
- If step-up assurance for an MFA-enrolled user is a hard requirement for your deployment, a backend proxy driven by a raw refresh_token grant is the wrong shape — route the user through an interactive /authorize redirect when step-up is needed, rather than disabling the tenant policy to make a background exchange succeed, as this demo had to.