{"id":28893735,"url":"https://github.com/rrbarrero/auth0-toy","last_synced_at":"2025-07-12T16:37:40.512Z","repository":{"id":298474441,"uuid":"999681383","full_name":"rrbarrero/auth0-toy","owner":"rrbarrero","description":"FastApi, React and Auth0 toy project","archived":false,"fork":false,"pushed_at":"2025-06-13T09:35:38.000Z","size":267,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-06-21T03:09:08.788Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rrbarrero.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-10T16:12:06.000Z","updated_at":"2025-06-13T09:35:42.000Z","dependencies_parsed_at":"2025-06-11T09:54:32.132Z","dependency_job_id":"5c27440f-272e-4af9-8460-b2a67d26da45","html_url":"https://github.com/rrbarrero/auth0-toy","commit_stats":null,"previous_names":["rrbarrero/auth0-toy"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/rrbarrero/auth0-toy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rrbarrero%2Fauth0-toy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rrbarrero%2Fauth0-toy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rrbarrero%2Fauth0-toy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rrbarrero%2Fauth0-toy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rrbarrero","download_url":"https://codeload.github.com/rrbarrero/auth0-toy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rrbarrero%2Fauth0-toy/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265024279,"owners_count":23699589,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-06-21T03:08:48.509Z","updated_at":"2025-07-12T16:37:40.506Z","avatar_url":"https://github.com/rrbarrero.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# React × FastAPI × Auth0 – Proof of Concept\n\nA very small PoC that shows how to:\n\n* authenticate a **React (Vite) Single-Page-Application** with Auth0  \n* secure a **FastAPI** backend with the same tokens  \n* enforce **role-based access** via a custom claim inside the `access_token`\n\n---\n## Demo 📸\n\n| Admin view | Regular user view |\n|------------|------------------|\n| ![Admin card](assets/admin_view.png) | ![User card](assets/user_view.png) |\n\n*If the logged user has the custom claim `http://localhost:3000/role=admin`, the “Admin Profile” card is displayed and the request to `/api/private-scoped-admin` succeeds.  \nOtherwise the card shows a friendly “Only admins can see this card.” message.*\n\n---\n\n## Flow\n```mermaid\ngraph TD\n    subgraph SPA\n        A[User clicks Log in] --\u003e B[Auth0Provider to /authorize]\n    end\n\n    subgraph Auth0\n        B --\u003e C[Auth0 Universal Login]\n        C --\u003e D{User authenticates}\n        D --\u003e E[Redirect back with code and state]\n        E --\u003e F[SPA exchanges code for tokens PKCE]\n        F --\u003e G[Post-login Action adds role claim]\n    end\n\n    F --\u003e H((Access \u0026 ID tokens))\n\n    H --\u003e I[GET\u0026nbsp;/api/private]\n    I --\u003e J{FastAPI VerifyToken}\n    J --\u003e K[200 OK]\n\n    H --\u003e L[GET\u0026nbsp;/api/private-scoped-admin]\n    L --\u003e M{VerifyToken and role admin?}\n    M --\u003e|yes| N[\"200 OK admin JSON\"]\n    M --\u003e|no| O[403 Forbidden]\n```\n---\n\n## Stack\n\n| Layer      | Tech | Notes |\n|------------|------|-------|\n| **SPA**    | React 18 + Vite + TypeScript | Authentication handled by `@auth0/auth0-react`. |\n| **Backend**| FastAPI + Uvicorn | JWT validation + fine-grained scope checks. |\n| **Auth**   | Auth0 | Custom Action adds a namespaced `role` claim to the token. |\n\n---\n\n## How it works\n\n1. **Login ↗ Auth0.**  \n   The SPA requests `audience=http://localhost:8000` and the scopes `openid profile email read:messages`.  \n2. **Auth0 Action** injects  \n   ```json\n   \"http://localhost:3000/role\": \"admin\"   // or \"user\" into every access- and ID-token.\n3. FastAPI dependency VerifyToken validates the token (signatures, issuer, audience, scopes).\n\nEndpoints can additionally check the custom role claim:\n\n```python\nif payload.get(\"http://localhost:3000/role\") != \"admin\":\n    raise HTTPException(403, \"Access denied\")\n\n```\nReact calls the backend with fetch and the bearer token returned by\ngetAccessTokenSilently().\n\nUI updates: if the call succeeds the JSON is rendered; if it fails (403) an error is shown.\n\n## Quick start 🚀\n### 1. Prerequisites\n- Docker\n- An Auth0 tenant (free tier is fine)\n\n### 2. Clone \u0026 install\n- git clone git@github.com:rrbarrero/auth0-toy.git\n- cd auth0-toy.git\n\n### 3. Create two .env files\n\u003cdetails\u003e \u003csummary\u003efe/.env\u003c/summary\u003e\n\u003cpre\u003eVITE_DOMAIN=dev-xxxxxxxx.eu.auth0.com\nVITE_CLIENT_ID=YOUR_SPA_CLIENT_ID\nVITE_AUDIENCE=http://localhost:8000\nVITE_SCOPE=openid profile email read:messages\u003c/pre\u003e\n\u003c/details\u003e \u003cdetails\u003e \u003csummary\u003ebe/.env\u003c/summary\u003e\n\u003cpre\u003eAUTH0_DOMAIN=dev-xxxxxxxx.eu.auth0.com\nAUTH0_API_AUDIENCE=http://localhost:8000\nAUTH0_ISSUER=https://dev-xxxxxxxx.eu.auth0.com\nAUTH0_ALGORITHMS=RS256\nAPP_NAME_NAMESPACE=http://localhost:3000    # same namespace used in the Action\u003c/pre\u003e\n\u003c/details\u003e\n\n### 4. Run\n- make start\n\n\nLog in with a user that has role=admin in its App Metadata to see both cards.\n\nProtected routes\nEndpoint\tProtection\tNotes\n\n- /api/private\ttoken only\tAny authenticated user.\n- /api/private-scoped\ttoken + scope read:messages\tDemonstrates scope check.\n- /api/private-scoped-admin\ttoken + scope + **role admin    Full RBAC example**.\n\n## Custom claim \u0026 Action\n\n```js\n// Auth0 ▸ Actions ▸ Post-Login\nexports.onExecutePostLogin = async (event, api) =\u003e {\n  const ns = 'http://localhost:3000/';\n  const role = event.user.app_metadata?.role || 'user';\n\n  api.accessToken.setCustomClaim(`${ns}role`, role);\n  api.idToken.setCustomClaim(`${ns}role`, role);\n};\n\n```\nUse a namespace you control to avoid collisions with standard claims.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frrbarrero%2Fauth0-toy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frrbarrero%2Fauth0-toy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frrbarrero%2Fauth0-toy/lists"}