├── .eslintrc.js ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── Bug Report.yml │ ├── Feature Request.yml │ └── config.yml ├── actions │ ├── build │ │ └── action.yml │ ├── get-prerelease │ │ └── action.yml │ ├── get-release-notes │ │ └── action.yml │ ├── get-version │ │ └── action.yml │ ├── npm-publish │ │ └── action.yml │ ├── release-create │ │ └── action.yml │ ├── rl-scanner │ │ └── action.yml │ └── tag-exists │ │ └── action.yml ├── dependabot.yml ├── stale.yml └── workflows │ ├── browserstack.yml │ ├── codeql.yml │ ├── integration.yml │ ├── npm-release.yml │ ├── release.yml │ ├── rl-secure.yml │ ├── semgrep.yml │ ├── snyk.yml │ └── test.yml ├── .gitignore ├── .husky └── pre-commit ├── .prettierignore ├── .prettierrc ├── .semgrepignore ├── .shiprc ├── .version ├── CHANGELOG.md ├── CONTRIBUTING.md ├── EXAMPLES.md ├── FAQ.md ├── Jenkinsfile ├── LICENSE ├── MIGRATION_GUIDE.md ├── README.md ├── TROUBLESHOOTING.md ├── __mocks__ └── @auth0 │ └── auth0-spa-js.tsx ├── __tests__ ├── auth-provider.test.tsx ├── auth-reducer.test.tsx ├── errors.test.tsx ├── helpers.tsx ├── ssr.test.tsx ├── use-auth.test.tsx ├── utils.test.tsx ├── with-auth0.test.tsx └── with-authentication-required.test.tsx ├── browserstack.json ├── codecov.yml ├── cypress-bs.config.js ├── cypress.config.js ├── cypress ├── e2e │ ├── smoke-bs.cy.ts │ └── smoke.cy.ts └── tsconfig.json ├── docs ├── .nojekyll ├── assets │ ├── highlight.css │ ├── icons.js │ ├── icons.svg │ ├── main.js │ ├── navigation.js │ ├── search.js │ └── style.css ├── classes │ ├── AuthenticationError.html │ ├── GenericError.html │ ├── InMemoryCache.html │ ├── LocalStorageCache.html │ ├── MfaRequiredError.html │ ├── MissingRefreshTokenError.html │ ├── OAuthError.html │ ├── PopupCancelledError.html │ ├── PopupTimeoutError.html │ ├── TimeoutError.html │ └── User.html ├── functions │ ├── Auth0Context.html │ ├── Auth0Provider.html │ ├── useAuth0.html │ ├── withAuth0.html │ └── withAuthenticationRequired.html ├── hierarchy.html ├── index.html ├── interfaces │ ├── Auth0ContextInterface.html │ ├── Auth0ProviderOptions.html │ ├── AuthorizationParams.html │ ├── GetTokenSilentlyOptions.html │ ├── GetTokenWithPopupOptions.html │ ├── ICache.html │ ├── IdToken.html │ ├── LogoutOptions.html │ ├── LogoutUrlOptions.html │ ├── PopupConfigOptions.html │ ├── PopupLoginOptions.html │ ├── RedirectLoginOptions.html │ ├── WithAuth0Props.html │ └── WithAuthenticationRequiredOptions.html ├── modules.html └── types │ ├── AppState.html │ ├── CacheLocation.html │ └── Cacheable.html ├── examples ├── README.md ├── cra-react-router │ ├── .env.sample │ ├── .gitignore │ ├── README.md │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ └── index.html │ ├── src │ │ ├── App.css │ │ ├── App.tsx │ │ ├── Error.tsx │ │ ├── Loading.tsx │ │ ├── Nav.tsx │ │ ├── Users.tsx │ │ ├── index.tsx │ │ ├── react-app-env.d.ts │ │ └── use-api.ts │ └── tsconfig.json ├── gatsby-app │ ├── .env.development.sample │ ├── .eslintrc │ ├── .gitignore │ ├── .prettierignore │ ├── .prettierrc │ ├── README.md │ ├── gatsby-browser.js │ ├── gatsby-config.js │ ├── package.json │ └── src │ │ ├── components │ │ ├── App.css │ │ ├── Error.js │ │ ├── Loading.js │ │ ├── Nav.js │ │ └── Users.js │ │ ├── hooks │ │ └── use-api.js │ │ └── pages │ │ ├── index.js │ │ └── users.js ├── nextjs-app │ ├── .env.sample │ ├── .gitignore │ ├── README.md │ ├── components │ │ ├── App.css │ │ ├── Error.js │ │ ├── Loading.js │ │ └── Nav.js │ ├── hooks │ │ └── use-api.js │ ├── package.json │ └── pages │ │ ├── _app.js │ │ ├── _document.js │ │ ├── index.js │ │ └── users.js └── users-api │ ├── .env.sample │ ├── README.md │ ├── package-lock.json │ ├── package.json │ └── server.js ├── jest.config.js ├── opslevel.yml ├── package-lock.json ├── package.json ├── rollup.config.mjs ├── scripts └── oidc-provider.mjs ├── src ├── auth-state.tsx ├── auth0-context.tsx ├── auth0-provider.tsx ├── errors.tsx ├── index.tsx ├── reducer.tsx ├── use-auth0.tsx ├── utils.tsx ├── with-auth0.tsx └── with-authentication-required.tsx ├── static └── index.html ├── tsconfig.json └── typedoc.js /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | parserOptions: { 4 | ecmaVersion: 2020, 5 | sourceType: 'module', 6 | ecmaFeatures: { 7 | jsx: true, 8 | }, 9 | }, 10 | settings: { 11 | react: { 12 | version: 'detect', 13 | }, 14 | }, 15 | extends: [ 16 | 'plugin:react/recommended', 17 | 'plugin:@typescript-eslint/recommended', 18 | 'plugin:react-hooks/recommended', 19 | ], 20 | rules: { 21 | '@typescript-eslint/camelcase': 'off', 22 | }, 23 | ignorePatterns: ['examples/**'], 24 | overrides: [ 25 | { 26 | files: ['*.js'], 27 | rules: { 28 | '@typescript-eslint/no-var-requires': 'off', 29 | }, 30 | }, 31 | ], 32 | }; 33 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @auth0/project-dx-sdks-engineer-codeowner 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Bug Report.yml: -------------------------------------------------------------------------------- 1 | name: 🐞 Report a bug 2 | description: Have you found a bug or issue? Create a bug report for this library 3 | labels: ["bug"] 4 | 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | **Please do not report security vulnerabilities here**. The [Responsible Disclosure Program](https://auth0.com/responsible-disclosure-policy) details the procedure for disclosing security issues. 10 | 11 | - type: checkboxes 12 | id: checklist 13 | attributes: 14 | label: Checklist 15 | options: 16 | - label: The issue can be reproduced in the [auth0-react sample app](https://github.com/auth0-samples/auth0-react-samples/tree/master/Sample-01) (or N/A). 17 | required: true 18 | - label: I have looked into the [Readme](https://github.com/auth0/auth0-react#readme), [Examples](https://github.com/auth0/auth0-react/blob/main/EXAMPLES.md), and [FAQ](https://github.com/auth0/auth0-react/blob/main/FAQ.md) and have not found a suitable solution or answer. 19 | required: true 20 | - label: I have looked into the [API documentation](https://auth0.github.io/auth0-react/) and have not found a suitable solution or answer. 21 | required: true 22 | - label: I have searched the [issues](https://github.com/auth0/auth0-react/issues) and have not found a suitable solution or answer. 23 | required: true 24 | - label: I have searched the [Auth0 Community](https://community.auth0.com) forums and have not found a suitable solution or answer. 25 | required: true 26 | - label: I agree to the terms within the [Auth0 Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md). 27 | required: true 28 | 29 | - type: textarea 30 | id: description 31 | attributes: 32 | label: Description 33 | description: Provide a clear and concise description of the issue, including what you expected to happen. 34 | validations: 35 | required: true 36 | 37 | - type: textarea 38 | id: reproduction 39 | attributes: 40 | label: Reproduction 41 | description: Detail the steps taken to reproduce this error, and whether this issue can be reproduced consistently or if it is intermittent. 42 | placeholder: | 43 | 1. Step 1... 44 | 2. Step 2... 45 | 3. ... 46 | validations: 47 | required: true 48 | 49 | - type: textarea 50 | id: additional-context 51 | attributes: 52 | label: Additional context 53 | description: Other libraries that might be involved, or any other relevant information you think would be useful. 54 | validations: 55 | required: false 56 | 57 | - type: input 58 | id: environment-version 59 | attributes: 60 | label: auth0-react version 61 | validations: 62 | required: true 63 | 64 | - type: input 65 | id: environment-react-version 66 | attributes: 67 | label: React version 68 | validations: 69 | required: true 70 | 71 | - type: dropdown 72 | id: environment-browser 73 | attributes: 74 | label: Which browsers have you tested in? 75 | multiple: true 76 | options: 77 | - Chrome 78 | - Edge 79 | - Safari 80 | - Firefox 81 | - Opera 82 | - Other 83 | validations: 84 | required: true 85 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature Request.yml: -------------------------------------------------------------------------------- 1 | name: 🧩 Feature request 2 | description: Suggest an idea or a feature for this library 3 | labels: ["feature request"] 4 | 5 | body: 6 | - type: checkboxes 7 | id: checklist 8 | attributes: 9 | label: Checklist 10 | options: 11 | - label: I have looked into the [Readme](https://github.com/auth0/auth0-react#readme), [Examples](https://github.com/auth0/auth0-react/blob/main/EXAMPLES.md), and [FAQ](https://github.com/auth0/auth0-react/blob/main/FAQ.md) and have not found a suitable solution or answer. 12 | required: true 13 | - label: I have looked into the [API documentation](https://auth0.github.io/auth0-react/) and have not found a suitable solution or answer. 14 | required: true 15 | - label: I have searched the [issues](https://github.com/auth0/auth0-react/issues) and have not found a suitable solution or answer. 16 | required: true 17 | - label: I have searched the [Auth0 Community](https://community.auth0.com) forums and have not found a suitable solution or answer. 18 | required: true 19 | - label: I agree to the terms within the [Auth0 Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md). 20 | required: true 21 | 22 | - type: textarea 23 | id: description 24 | attributes: 25 | label: Describe the problem you'd like to have solved 26 | description: A clear and concise description of what the problem is. 27 | placeholder: I'm always frustrated when... 28 | validations: 29 | required: true 30 | 31 | - type: textarea 32 | id: ideal-solution 33 | attributes: 34 | label: Describe the ideal solution 35 | description: A clear and concise description of what you want to happen. 36 | validations: 37 | required: true 38 | 39 | - type: textarea 40 | id: alternatives-and-workarounds 41 | attributes: 42 | label: Alternatives and current workarounds 43 | description: A clear and concise description of any alternatives you've considered or any workarounds that are currently in place. 44 | validations: 45 | required: false 46 | 47 | - type: textarea 48 | id: additional-context 49 | attributes: 50 | label: Additional context 51 | description: Add any other context or screenshots about the feature request here. 52 | validations: 53 | required: false 54 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Auth0 Community 4 | url: https://community.auth0.com 5 | about: Discuss this SDK in the Auth0 Community forums 6 | - name: FAQ 7 | url: https://github.com/auth0/auth0-react/blob/main/FAQ.md 8 | about: Read the FAQ to get answers to common issues 9 | - name: SDK API Documentation 10 | url: https://auth0.github.io/auth0-react/ 11 | about: Read the API documentation for this SDK 12 | - name: Library Documentation 13 | url: https://auth0.com/docs/libraries/auth0-react 14 | about: Read the library docs on Auth0.com 15 | -------------------------------------------------------------------------------- /.github/actions/build/action.yml: -------------------------------------------------------------------------------- 1 | name: Build package 2 | description: Build the SDK package 3 | 4 | inputs: 5 | node: 6 | description: The Node version to use 7 | required: false 8 | default: 18 9 | 10 | runs: 11 | using: composite 12 | 13 | steps: 14 | - name: Setup Node 15 | uses: actions/setup-node@v3 16 | with: 17 | node-version: ${{ inputs.node }} 18 | cache: 'npm' 19 | 20 | - name: Install dependencies 21 | shell: bash 22 | run: npm ci --include=dev 23 | 24 | - name: Build package 25 | shell: bash 26 | run: npm run build 27 | -------------------------------------------------------------------------------- /.github/actions/get-prerelease/action.yml: -------------------------------------------------------------------------------- 1 | name: Return a boolean indicating if the version contains prerelease identifiers 2 | 3 | # 4 | # Returns a simple true/false boolean indicating whether the version indicates it's a prerelease or not. 5 | # 6 | # TODO: Remove once the common repo is public. 7 | # 8 | 9 | inputs: 10 | version: 11 | required: true 12 | 13 | outputs: 14 | prerelease: 15 | value: ${{ steps.get_prerelease.outputs.PRERELEASE }} 16 | 17 | runs: 18 | using: composite 19 | 20 | steps: 21 | - id: get_prerelease 22 | shell: bash 23 | run: | 24 | if [[ "${VERSION}" == *"beta"* || "${VERSION}" == *"alpha"* ]]; then 25 | echo "PRERELEASE=true" >> $GITHUB_OUTPUT 26 | else 27 | echo "PRERELEASE=false" >> $GITHUB_OUTPUT 28 | fi 29 | env: 30 | VERSION: ${{ inputs.version }} 31 | -------------------------------------------------------------------------------- /.github/actions/get-release-notes/action.yml: -------------------------------------------------------------------------------- 1 | name: Return the release notes extracted from the body of the PR associated with the release. 2 | 3 | # 4 | # Returns the release notes from the content of a pull request linked to a release branch. It expects the branch name to be in the format release/vX.Y.Z, release/X.Y.Z, release/vX.Y.Z-beta.N. etc. 5 | # 6 | # TODO: Remove once the common repo is public. 7 | # 8 | inputs: 9 | version: 10 | required: true 11 | repo_name: 12 | required: false 13 | repo_owner: 14 | required: true 15 | token: 16 | required: true 17 | 18 | outputs: 19 | release-notes: 20 | value: ${{ steps.get_release_notes.outputs.RELEASE_NOTES }} 21 | 22 | runs: 23 | using: composite 24 | 25 | steps: 26 | - uses: actions/github-script@v7 27 | id: get_release_notes 28 | with: 29 | result-encoding: string 30 | script: | 31 | const { data: pulls } = await github.rest.pulls.list({ 32 | owner: process.env.REPO_OWNER, 33 | repo: process.env.REPO_NAME, 34 | state: 'all', 35 | head: `${process.env.REPO_OWNER}:release/${process.env.VERSION}`, 36 | }); 37 | core.setOutput('RELEASE_NOTES', pulls[0].body); 38 | env: 39 | GITHUB_TOKEN: ${{ inputs.token }} 40 | REPO_OWNER: ${{ inputs.repo_owner }} 41 | REPO_NAME: ${{ inputs.repo_name }} 42 | VERSION: ${{ inputs.version }} -------------------------------------------------------------------------------- /.github/actions/get-version/action.yml: -------------------------------------------------------------------------------- 1 | name: Return the version extracted from the branch name 2 | 3 | # 4 | # Returns the version from the .version file. 5 | # 6 | # TODO: Remove once the common repo is public. 7 | # 8 | 9 | outputs: 10 | version: 11 | value: ${{ steps.get_version.outputs.VERSION }} 12 | 13 | runs: 14 | using: composite 15 | 16 | steps: 17 | - id: get_version 18 | shell: bash 19 | run: | 20 | VERSION=$(head -1 .version) 21 | echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT 22 | -------------------------------------------------------------------------------- /.github/actions/npm-publish/action.yml: -------------------------------------------------------------------------------- 1 | name: Publish release to npm 2 | 3 | inputs: 4 | node-version: 5 | required: true 6 | npm-token: 7 | required: true 8 | version: 9 | required: true 10 | require-build: 11 | default: true 12 | release-directory: 13 | default: './' 14 | 15 | runs: 16 | using: composite 17 | 18 | steps: 19 | - name: Checkout code 20 | uses: actions/checkout@v4 21 | 22 | - name: Setup Node 23 | uses: actions/setup-node@v4 24 | with: 25 | node-version: ${{ inputs.node-version }} 26 | cache: 'npm' 27 | registry-url: 'https://registry.npmjs.org' 28 | 29 | - name: Install dependencies 30 | shell: bash 31 | run: npm ci --include=dev 32 | 33 | - name: Build package 34 | if: inputs.require-build == 'true' 35 | shell: bash 36 | run: npm run build 37 | 38 | - name: Publish release to NPM 39 | shell: bash 40 | working-directory: ${{ inputs.release-directory }} 41 | run: | 42 | if [[ "${VERSION}" == *"beta"* ]]; then 43 | TAG="beta" 44 | elif [[ "${VERSION}" == *"alpha"* ]]; then 45 | TAG="alpha" 46 | else 47 | TAG="latest" 48 | fi 49 | npm publish --provenance --tag $TAG 50 | env: 51 | NODE_AUTH_TOKEN: ${{ inputs.npm-token }} 52 | VERSION: ${{ inputs.version }} -------------------------------------------------------------------------------- /.github/actions/release-create/action.yml: -------------------------------------------------------------------------------- 1 | name: Create a GitHub release 2 | 3 | # 4 | # Creates a GitHub release with the given version. 5 | # 6 | # TODO: Remove once the common repo is public. 7 | # 8 | 9 | inputs: 10 | token: 11 | required: true 12 | files: 13 | required: false 14 | name: 15 | required: true 16 | body: 17 | required: true 18 | tag: 19 | required: true 20 | commit: 21 | required: true 22 | draft: 23 | default: false 24 | required: false 25 | prerelease: 26 | default: false 27 | required: false 28 | fail_on_unmatched_files: 29 | default: true 30 | required: false 31 | 32 | runs: 33 | using: composite 34 | 35 | steps: 36 | - uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 37 | with: 38 | body: ${{ inputs.body }} 39 | name: ${{ inputs.name }} 40 | tag_name: ${{ inputs.tag }} 41 | target_commitish: ${{ inputs.commit }} 42 | draft: ${{ inputs.draft }} 43 | prerelease: ${{ inputs.prerelease }} 44 | fail_on_unmatched_files: ${{ inputs.fail_on_unmatched_files }} 45 | files: ${{ inputs.files }} 46 | env: 47 | GITHUB_TOKEN: ${{ inputs.token }} 48 | -------------------------------------------------------------------------------- /.github/actions/rl-scanner/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Reversing Labs Scanner' 2 | description: 'Runs the Reversing Labs scanner on a specified artifact.' 3 | inputs: 4 | artifact-path: 5 | description: 'Path to the artifact to be scanned.' 6 | required: true 7 | version: 8 | description: 'Version of the artifact.' 9 | required: true 10 | 11 | runs: 12 | using: 'composite' 13 | steps: 14 | - name: Set up Python 15 | uses: actions/setup-python@v4 16 | with: 17 | python-version: '3.10' 18 | 19 | - name: Install Python dependencies 20 | shell: bash 21 | run: | 22 | pip install boto3 requests 23 | 24 | - name: Configure AWS credentials 25 | uses: aws-actions/configure-aws-credentials@v1 26 | with: 27 | role-to-assume: ${{ env.PRODSEC_TOOLS_ARN }} 28 | aws-region: us-east-1 29 | mask-aws-account-id: true 30 | 31 | - name: Install RL Wrapper 32 | shell: bash 33 | run: | 34 | pip install rl-wrapper>=1.0.0 --index-url "https://${{ env.PRODSEC_TOOLS_USER }}:${{ env.PRODSEC_TOOLS_TOKEN }}@a0us.jfrog.io/artifactory/api/pypi/python-local/simple" 35 | 36 | - name: Run RL Scanner 37 | shell: bash 38 | env: 39 | RLSECURE_LICENSE: ${{ env.RLSECURE_LICENSE }} 40 | RLSECURE_SITE_KEY: ${{ env.RLSECURE_SITE_KEY }} 41 | SIGNAL_HANDLER_TOKEN: ${{ env.SIGNAL_HANDLER_TOKEN }} 42 | PYTHONUNBUFFERED: 1 43 | run: | 44 | if [ ! -f "${{ inputs.artifact-path }}" ]; then 45 | echo "Artifact not found: ${{ inputs.artifact-path }}" 46 | exit 1 47 | fi 48 | 49 | rl-wrapper \ 50 | --artifact "${{ inputs.artifact-path }}" \ 51 | --name "${{ github.event.repository.name }}" \ 52 | --version "${{ inputs.version }}" \ 53 | --repository "${{ github.repository }}" \ 54 | --commit "${{ github.sha }}" \ 55 | --build-env "github_actions" \ 56 | --suppress_output 57 | 58 | # Check the outcome of the scanner 59 | if [ $? -ne 0 ]; then 60 | echo "RL Scanner failed." 61 | echo "scan-status=failed" >> $GITHUB_ENV 62 | exit 1 63 | else 64 | echo "RL Scanner passed." 65 | echo "scan-status=success" >> $GITHUB_ENV 66 | fi 67 | 68 | outputs: 69 | scan-status: 70 | description: 'The outcome of the scan process.' 71 | value: ${{ env.scan-status }} 72 | -------------------------------------------------------------------------------- /.github/actions/tag-exists/action.yml: -------------------------------------------------------------------------------- 1 | name: Return a boolean indicating if a tag already exists for the repository 2 | 3 | # 4 | # Returns a simple true/false boolean indicating whether the tag exists or not. 5 | # 6 | # TODO: Remove once the common repo is public. 7 | # 8 | 9 | inputs: 10 | token: 11 | required: true 12 | tag: 13 | required: true 14 | 15 | outputs: 16 | exists: 17 | description: 'Whether the tag exists or not' 18 | value: ${{ steps.tag-exists.outputs.EXISTS }} 19 | 20 | runs: 21 | using: composite 22 | 23 | steps: 24 | - id: tag-exists 25 | shell: bash 26 | run: | 27 | GET_API_URL="https://api.github.com/repos/${GITHUB_REPOSITORY}/git/ref/tags/${TAG_NAME}" 28 | http_status_code=$(curl -LI $GET_API_URL -o /dev/null -w '%{http_code}\n' -s -H "Authorization: token ${GITHUB_TOKEN}") 29 | if [ "$http_status_code" -ne "404" ] ; then 30 | echo "EXISTS=true" >> $GITHUB_OUTPUT 31 | else 32 | echo "EXISTS=false" >> $GITHUB_OUTPUT 33 | fi 34 | env: 35 | TAG_NAME: ${{ inputs.tag }} 36 | GITHUB_TOKEN: ${{ inputs.token }} 37 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: 'github-actions' 4 | directory: '/' 5 | schedule: 6 | interval: 'daily' 7 | - package-ecosystem: 'npm' 8 | directory: '/' 9 | schedule: 10 | interval: 'daily' 11 | ignore: 12 | - dependency-name: "*" 13 | update-types: ["version-update:semver-major"] 14 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Configuration for probot-stale - https://github.com/probot/stale 2 | 3 | # Number of days of inactivity before an Issue or Pull Request becomes stale 4 | daysUntilStale: 30 5 | 6 | # Number of days of inactivity before an Issue or Pull Request with the stale label is closed. 7 | daysUntilClose: 7 8 | 9 | # Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) 10 | onlyLabels: 11 | - 'waiting for customer' 12 | 13 | # Ignore issues in projects 14 | exemptProjects: true 15 | 16 | # Ignore issues and PRs in milestones 17 | exemptMilestones: true 18 | 19 | # Set to true to ignore issues with an assignee 20 | exemptAssignees: true 21 | 22 | # Label to use when marking as stale 23 | staleLabel: closed:stale 24 | 25 | # Comment to post when marking as stale. Set to `false` to disable 26 | markComment: > 27 | This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you have not received a response for our team (apologies for the delay) and this is still a blocker, please reply with additional information or just a ping. Thank you for your contribution! 🙇‍♂️ 28 | -------------------------------------------------------------------------------- /.github/workflows/browserstack.yml: -------------------------------------------------------------------------------- 1 | name: Browserstack 2 | 3 | on: 4 | merge_group: 5 | workflow_dispatch: 6 | pull_request: 7 | types: 8 | - opened 9 | - synchronize 10 | push: 11 | branches: 12 | - main 13 | 14 | permissions: 15 | contents: read 16 | 17 | concurrency: 18 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} 19 | cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} 20 | 21 | env: 22 | NODE_VERSION: 18 23 | 24 | jobs: 25 | 26 | browserstack: 27 | 28 | name: BrowserStack Tests 29 | runs-on: ubuntu-latest 30 | 31 | steps: 32 | - name: Checkout code 33 | uses: actions/checkout@v4 34 | with: 35 | ref: ${{ github.event.pull_request.head.sha || github.ref }} 36 | 37 | - name: Setup Node 38 | uses: actions/setup-node@v4 39 | with: 40 | node-version: ${{ env.NODE_VERSION }} 41 | cache: npm 42 | 43 | - name: Build package 44 | uses: ./.github/actions/build 45 | with: 46 | node: ${{ env.NODE_VERSION }} 47 | 48 | - name: Run tests 49 | shell: bash 50 | run: npx concurrently --raw --kill-others --success first "npm:start" "wait-on http://127.0.0.1:3000/ && browserstack-cypress run --build-name ${{ github.event.pull_request.head.sha || github.ref }} --no-wrap --specs "cypress/e2e/smoke-bs.cy.ts"" 51 | env: 52 | BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }} 53 | BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }} 54 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: CodeQL 2 | 3 | on: 4 | merge_group: 5 | pull_request: 6 | types: 7 | - opened 8 | - synchronize 9 | push: 10 | branches: 11 | - main 12 | - beta 13 | schedule: 14 | - cron: '37 10 * * 2' 15 | 16 | permissions: 17 | actions: read 18 | contents: read 19 | security-events: write 20 | 21 | concurrency: 22 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} 23 | cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} 24 | 25 | jobs: 26 | analyze: 27 | name: Check for Vulnerabilities 28 | runs-on: ubuntu-latest 29 | 30 | strategy: 31 | fail-fast: false 32 | matrix: 33 | language: [javascript] 34 | 35 | steps: 36 | - if: github.actor == 'dependabot[bot]' || github.event_name == 'merge_group' 37 | run: exit 0 # Skip unnecessary test runs for dependabot and merge queues. Artifically flag as successful, as this is a required check for branch protection. 38 | 39 | - name: Checkout 40 | uses: actions/checkout@v4 41 | 42 | - name: Initialize CodeQL 43 | uses: github/codeql-action/init@v3 44 | with: 45 | languages: ${{ matrix.language }} 46 | queries: +security-and-quality 47 | 48 | - name: Autobuild 49 | uses: github/codeql-action/autobuild@v3 50 | 51 | - name: Perform CodeQL Analysis 52 | uses: github/codeql-action/analyze@v3 53 | with: 54 | category: '/language:${{ matrix.language }}' 55 | -------------------------------------------------------------------------------- /.github/workflows/integration.yml: -------------------------------------------------------------------------------- 1 | name: Integration Tests 2 | 3 | on: 4 | merge_group: 5 | workflow_dispatch: 6 | pull_request: 7 | types: 8 | - opened 9 | - synchronize 10 | push: 11 | branches: 12 | - main 13 | 14 | permissions: 15 | contents: read 16 | 17 | concurrency: 18 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} 19 | cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} 20 | 21 | env: 22 | NODE_VERSION: 18 23 | 24 | jobs: 25 | test-examples: 26 | name: Run example tests 27 | runs-on: ubuntu-latest 28 | 29 | env: 30 | SKIP_PREFLIGHT_CHECK: true 31 | CYPRESS_USER_EMAIL: ${{secrets.CYPRESS_USER_EMAIL}} 32 | CYPRESS_USER_PASSWORD: ${{secrets.CYPRESS_USER_PASSWORD}} 33 | REACT_APP_DOMAIN: ${{secrets.TEST_DOMAIN}} 34 | REACT_APP_CLIENT_ID: ${{secrets.TEST_CLIENT_ID}} 35 | REACT_APP_AUDIENCE: ${{secrets.TEST_AUDIENCE}} 36 | GATSBY_DOMAIN: ${{secrets.TEST_DOMAIN}} 37 | GATSBY_CLIENT_ID: ${{secrets.TEST_CLIENT_ID}} 38 | GATSBY_AUDIENCE: ${{secrets.TEST_AUDIENCE}} 39 | NEXT_PUBLIC_DOMAIN: ${{secrets.TEST_DOMAIN}} 40 | NEXT_PUBLIC_CLIENT_ID: ${{secrets.TEST_CLIENT_ID}} 41 | NEXT_PUBLIC_AUDIENCE: ${{secrets.TEST_AUDIENCE}} 42 | DOMAIN: ${{secrets.TEST_DOMAIN}} 43 | AUDIENCE: ${{secrets.TEST_AUDIENCE}} 44 | 45 | steps: 46 | - name: Checkout code 47 | uses: actions/checkout@v4 48 | with: 49 | ref: ${{ github.event.pull_request.head.sha || github.ref }} 50 | 51 | - name: Install dependencies 52 | run: npm ci 53 | 54 | - name: Build SDK 55 | run: npm run build 56 | 57 | - name: Install examples 58 | run: npm run install:examples 59 | 60 | - name: Run integration test (CRA) 61 | run: npm run test:cra 62 | 63 | - name: Run integration test (NextJS) 64 | run: npm run test:nextjs 65 | 66 | - name: Run integration test (Gatsby) 67 | run: npm run test:gatsby 68 | -------------------------------------------------------------------------------- /.github/workflows/npm-release.yml: -------------------------------------------------------------------------------- 1 | name: Create npm and GitHub Release 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | node-version: 7 | required: true 8 | type: string 9 | require-build: 10 | default: "true" 11 | type: string 12 | release-directory: 13 | default: './' 14 | type: string 15 | secrets: 16 | github-token: 17 | required: true 18 | npm-token: 19 | required: true 20 | 21 | jobs: 22 | release: 23 | if: github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.event.pull_request.merged && startsWith(github.event.pull_request.head.ref, 'release/')) 24 | runs-on: ubuntu-latest 25 | environment: release 26 | 27 | steps: 28 | # Checkout the code 29 | - uses: actions/checkout@v4 30 | with: 31 | fetch-depth: 0 32 | 33 | # Get the version from the branch name 34 | - id: get_version 35 | uses: ./.github/actions/get-version 36 | 37 | # Get the prerelease flag from the branch name 38 | - id: get_prerelease 39 | uses: ./.github/actions/get-prerelease 40 | with: 41 | version: ${{ steps.get_version.outputs.version }} 42 | 43 | # Get the release notes 44 | - id: get_release_notes 45 | uses: ./.github/actions/get-release-notes 46 | with: 47 | token: ${{ secrets.github-token }} 48 | version: ${{ steps.get_version.outputs.version }} 49 | repo_owner: ${{ github.repository_owner }} 50 | repo_name: ${{ github.event.repository.name }} 51 | 52 | # Check if the tag already exists 53 | - id: tag_exists 54 | uses: ./.github/actions/tag-exists 55 | with: 56 | tag: ${{ steps.get_version.outputs.version }} 57 | token: ${{ secrets.github-token }} 58 | 59 | # If the tag already exists, exit with an error 60 | - if: steps.tag_exists.outputs.exists == 'true' 61 | run: exit 1 62 | 63 | # Publish the release to our package manager 64 | - uses: ./.github/actions/npm-publish 65 | with: 66 | node-version: ${{ inputs.node-version }} 67 | require-build: ${{ inputs.require-build }} 68 | version: ${{ steps.get_version.outputs.version }} 69 | npm-token: ${{ secrets.npm-token }} 70 | release-directory: ${{ inputs.release-directory }} 71 | 72 | # Create a release for the tag 73 | - uses: ./.github/actions/release-create 74 | with: 75 | token: ${{ secrets.github-token }} 76 | name: ${{ steps.get_version.outputs.version }} 77 | body: ${{ steps.get_release_notes.outputs.release-notes }} 78 | tag: ${{ steps.get_version.outputs.version }} 79 | commit: ${{ github.sha }} 80 | prerelease: ${{ steps.get_prerelease.outputs.prerelease }} -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Create npm and GitHub Release 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - closed 7 | workflow_dispatch: 8 | permissions: 9 | contents: write 10 | id-token: write # For publishing to npm using --provenance 11 | 12 | ### TODO: Replace instances of './.github/workflows/' w/ `auth0/dx-sdk-actions/workflows/` and append `@latest` after the common `dx-sdk-actions` repo is made public. 13 | ### TODO: Also remove `get-prerelease`, `get-release-notes`, `get-version`, `npm-publish`, `release-create`, and `tag-exists` actions from this repo's .github/actions folder once the repo is public. 14 | ### TODO: Also remove `npm-release` workflow from this repo's .github/workflows folder once the repo is public. 15 | 16 | jobs: 17 | rl-scanner: 18 | uses: ./.github/workflows/rl-secure.yml 19 | with: 20 | node-version: 18 21 | artifact-name: 'auth0-react.tgz' 22 | secrets: 23 | RLSECURE_LICENSE: ${{ secrets.RLSECURE_LICENSE }} 24 | RLSECURE_SITE_KEY: ${{ secrets.RLSECURE_SITE_KEY }} 25 | SIGNAL_HANDLER_TOKEN: ${{ secrets.SIGNAL_HANDLER_TOKEN }} 26 | PRODSEC_TOOLS_USER: ${{ secrets.PRODSEC_TOOLS_USER }} 27 | PRODSEC_TOOLS_TOKEN: ${{ secrets.PRODSEC_TOOLS_TOKEN }} 28 | PRODSEC_TOOLS_ARN: ${{ secrets.PRODSEC_TOOLS_ARN }} 29 | release: 30 | uses: ./.github/workflows/npm-release.yml 31 | needs: rl-scanner 32 | with: 33 | node-version: 18 34 | require-build: true 35 | secrets: 36 | npm-token: ${{ secrets.NPM_TOKEN }} 37 | github-token: ${{ secrets.GITHUB_TOKEN }} 38 | -------------------------------------------------------------------------------- /.github/workflows/rl-secure.yml: -------------------------------------------------------------------------------- 1 | name: RL-Secure Workflow 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | node-version: 7 | required: true 8 | type: string 9 | artifact-name: 10 | required: true 11 | type: string 12 | secrets: 13 | RLSECURE_LICENSE: 14 | required: true 15 | RLSECURE_SITE_KEY: 16 | required: true 17 | SIGNAL_HANDLER_TOKEN: 18 | required: true 19 | PRODSEC_TOOLS_USER: 20 | required: true 21 | PRODSEC_TOOLS_TOKEN: 22 | required: true 23 | PRODSEC_TOOLS_ARN: 24 | required: true 25 | 26 | jobs: 27 | rl-scanner: 28 | name: Run Reversing Labs Scanner 29 | if: github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.event.pull_request.merged && startsWith(github.event.pull_request.head.ref, 'release/')) 30 | runs-on: ubuntu-latest 31 | outputs: 32 | scan-status: ${{ steps.rl-scan-conclusion.outcome }} 33 | 34 | steps: 35 | - name: Checkout code 36 | uses: actions/checkout@v4 37 | with: 38 | fetch-depth: 0 39 | 40 | - name: Build package 41 | uses: ./.github/actions/build 42 | with: 43 | node: ${{ inputs.node-version }} 44 | 45 | - name: Create tgz build artifact 46 | run: | 47 | tar -czvf ${{ inputs.artifact-name }} * 48 | 49 | - id: get_version 50 | uses: ./.github/actions/get-version 51 | 52 | - name: Run RL Scanner 53 | id: rl-scan-conclusion 54 | uses: ./.github/actions/rl-scanner 55 | with: 56 | artifact-path: "$(pwd)/${{ inputs.artifact-name }}" 57 | version: "${{ steps.get_version.outputs.version }}" 58 | env: 59 | RLSECURE_LICENSE: ${{ secrets.RLSECURE_LICENSE }} 60 | RLSECURE_SITE_KEY: ${{ secrets.RLSECURE_SITE_KEY }} 61 | SIGNAL_HANDLER_TOKEN: ${{ secrets.SIGNAL_HANDLER_TOKEN }} 62 | PRODSEC_TOOLS_USER: ${{ secrets.PRODSEC_TOOLS_USER }} 63 | PRODSEC_TOOLS_TOKEN: ${{ secrets.PRODSEC_TOOLS_TOKEN }} 64 | PRODSEC_TOOLS_ARN: ${{ secrets.PRODSEC_TOOLS_ARN }} 65 | 66 | - name: Output scan result 67 | run: echo "scan-status=${{ steps.rl-scan-conclusion.outcome }}" >> $GITHUB_ENV 68 | -------------------------------------------------------------------------------- /.github/workflows/semgrep.yml: -------------------------------------------------------------------------------- 1 | name: Semgrep 2 | 3 | on: 4 | merge_group: 5 | pull_request: 6 | types: 7 | - opened 8 | - synchronize 9 | push: 10 | branches: 11 | - main 12 | - beta 13 | schedule: 14 | - cron: '30 0 1,15 * *' 15 | 16 | permissions: 17 | contents: read 18 | 19 | concurrency: 20 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} 21 | cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} 22 | 23 | jobs: 24 | run: 25 | name: Check for Vulnerabilities 26 | runs-on: ubuntu-latest 27 | 28 | container: 29 | image: returntocorp/semgrep 30 | 31 | steps: 32 | - if: github.actor == 'dependabot[bot]' || github.event_name == 'merge_group' 33 | run: exit 0 # Skip unnecessary test runs for dependabot and merge queues. Artifically flag as successful, as this is a required check for branch protection. 34 | 35 | - uses: actions/checkout@v4 36 | with: 37 | ref: ${{ github.event.pull_request.head.sha || github.ref }} 38 | 39 | - run: semgrep ci 40 | env: 41 | SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} 42 | -------------------------------------------------------------------------------- /.github/workflows/snyk.yml: -------------------------------------------------------------------------------- 1 | name: Snyk 2 | 3 | on: 4 | merge_group: 5 | workflow_dispatch: 6 | pull_request: 7 | types: 8 | - opened 9 | - synchronize 10 | push: 11 | branches: 12 | - main 13 | - beta 14 | schedule: 15 | - cron: '30 0 1,15 * *' 16 | 17 | permissions: 18 | contents: read 19 | 20 | concurrency: 21 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} 22 | cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} 23 | 24 | jobs: 25 | check: 26 | 27 | name: Check for Vulnerabilities 28 | runs-on: ubuntu-latest 29 | 30 | steps: 31 | - if: github.actor == 'dependabot[bot]' || github.event_name == 'merge_group' 32 | run: exit 0 # Skip unnecessary test runs for dependabot and merge queues. Artifically flag as successful, as this is a required check for branch protection. 33 | 34 | - uses: actions/checkout@v4 35 | with: 36 | ref: ${{ github.event.pull_request.head.sha || github.ref }} 37 | 38 | - uses: snyk/actions/node@b98d498629f1c368650224d6d212bf7dfa89e4bf # pin@0.4.0 39 | env: 40 | SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} 41 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Unit Tests 2 | 3 | on: 4 | merge_group: 5 | workflow_dispatch: 6 | pull_request: 7 | branches: 8 | - main 9 | push: 10 | branches: 11 | - main 12 | 13 | permissions: 14 | contents: read 15 | 16 | concurrency: 17 | group: ${{ github.workflow }}-${{ github.ref }} 18 | cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} 19 | 20 | env: 21 | NODE_VERSION: 18 22 | CACHE_KEY: '${{ github.ref }}-${{ github.run_id }}-${{ github.run_attempt }}' 23 | 24 | jobs: 25 | build: 26 | name: Build Package 27 | runs-on: ubuntu-latest 28 | 29 | steps: 30 | - name: Checkout code 31 | uses: actions/checkout@v4 32 | with: 33 | ref: ${{ github.event.pull_request.head.sha || github.ref }} 34 | 35 | - name: Build package 36 | uses: ./.github/actions/build 37 | with: 38 | node: ${{ env.NODE_VERSION }} 39 | 40 | - name: Save build artifacts 41 | uses: actions/cache/save@v4 42 | with: 43 | path: . 44 | key: ${{ env.CACHE_KEY }} 45 | 46 | unit: 47 | needs: build # Require build to complete before running tests 48 | 49 | name: Run Tests 50 | runs-on: ubuntu-latest 51 | 52 | steps: 53 | - name: Checkout code 54 | uses: actions/checkout@v4 55 | 56 | - name: Setup Node 57 | uses: actions/setup-node@v4 58 | with: 59 | node-version: ${{ env.NODE_VERSION }} 60 | cache: npm 61 | 62 | - name: Restore build artifacts 63 | uses: actions/cache/restore@v4 64 | with: 65 | path: . 66 | key: ${{ env.CACHE_KEY }} 67 | 68 | - name: Run tests 69 | run: npm run test 70 | 71 | - name: Upload coverage 72 | uses: codecov/codecov-action@4fe8c5f003fae66aa5ebb77cfd3e7bfbbda0b6b0 # pin@3.1.5 73 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | 106 | .idea 107 | test-results 108 | 109 | cypress/screenshots 110 | cypress/videos 111 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx pretty-quick --staged 5 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | CHANGELOG.md 2 | docs 3 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "printWidth": 80 4 | } 5 | -------------------------------------------------------------------------------- /.semgrepignore: -------------------------------------------------------------------------------- 1 | .circleci/ 2 | .github/ 3 | __mocks__/ 4 | __tests__/ 5 | cypress/ 6 | docs/ 7 | examples/ 8 | static/ 9 | README.md 10 | -------------------------------------------------------------------------------- /.shiprc: -------------------------------------------------------------------------------- 1 | { 2 | "files": { 3 | ".version": [] 4 | }, 5 | "postbump": "npm run docs" 6 | } -------------------------------------------------------------------------------- /.version: -------------------------------------------------------------------------------- 1 | v2.3.0 -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | We appreciate feedback and contribution to this repo! Before you get started, please see [Auth0's general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md) 4 | 5 | ## Local development 6 | 7 | Install the dependencies and start the development server: 8 | 9 | ```bash 10 | npm install 11 | npm start 12 | ``` 13 | 14 | This will run a development server at http://localhost:3000 with a simple application that demonstrates the main features of the SDK. When you make changes the development server will live reload. 15 | 16 | You can change the default Auth0 tenant and application by editing the domain and clientId in [static/index.html](./static/index.html#L81-L82) 17 | 18 | ## Running the examples 19 | 20 | The examples are React applications and an Express API. To run the example apps see the instructions in [examples/README.md](./examples/README.md) 21 | 22 | ## Running the unit tests 23 | 24 | The unit tests use Jest and are run with: 25 | 26 | ```bash 27 | npm test 28 | ``` 29 | 30 | ## Running the integration tests 31 | 32 | The integration tests run against the examples, so you must follow the instructions to set up the examples in [examples/README.md](./examples/README.md) first. 33 | 34 | Then run: 35 | 36 | ```bash 37 | CYPRESS_USER_EMAIL={YOUR USER} CYPRESS_USER_PASSWORD={YOUR PW} npm run test:integration 38 | ``` 39 | 40 | `CYPRESS_USER_EMAIL` and `CYPRESS_USER_PASSWORD` should be the credentials of a user on your Auth0 tenant that has the `read:users` permissions on the audience you specified when setting up the examples. 41 | -------------------------------------------------------------------------------- /FAQ.md: -------------------------------------------------------------------------------- 1 | # Frequently Asked Questions 2 | 3 | **Note:** `auth0-react` uses [Auth0 SPA JS](https://github.com/auth0/auth0-spa-js) behind the scenes, so be sure to check [their FAQs](https://github.com/auth0/auth0-spa-js/blob/main/FAQ.md) too. 4 | 5 | 1. [User is not logged in after page refresh](#1-user-is-not-logged-in-after-page-refresh) 6 | 2. [User is not logged in after successful sign in with redirect](#2-user-is-not-logged-in-after-successful-sign-in-with-redirect) 7 | 8 | ## 1. User is not logged in after page refresh 9 | 10 | There are usually 2 reasons for this: 11 | 12 | **1. The user logged in with a Social Provider (like Google) and you are using the Auth0 Developer Keys** 13 | 14 | If you are using the [Classic Universal Login](https://auth0.com/docs/universal-login/classic) experience, [Silent Authentication](https://auth0.com/docs/authorization/configure-silent-authentication) won't work on the `/authorize` endpoint. This library uses Silent Authentication internally to check if a user is already signed in after page refresh, so that won't work either. You should either change to the [New Universal Login](https://auth0.com/docs/universal-login/new-experience) experience or [add your own keys](https://auth0.com/docs/connections/identity-providers-social) to that particular social connection. 15 | 16 | **2. You are using a browser like Safari or Brave that has Intelligent Tracking Prevention turned on by default** 17 | 18 | In this case Silent Authentication will not work because it relies on a hidden iframe being logged in to a different domain (usually `auth0.com`) and browsers with ITP do not allow third-party (eg iframed) cookies. There are 2 workarounds for this using [Rotating Refresh Tokens](https://auth0.com/docs/tokens/refresh-tokens/refresh-token-rotation) or [Custom Domains](https://auth0.com/docs/custom-domains) 19 | 20 | ## 2. User is not logged in after successful sign in with redirect 21 | 22 | If after successfully logging in, your user returns to your SPA and is still not authenticated, do _not_ refresh the page - go to the Network tab on Chrome and confirm that the POST to `oauth/token` resulted in an error `401 Unauthorized`. If this is the case, your tenant is most likely misconfigured. Go to your **Application Properties** in your application's settings in the [Auth0 Dashboard](https://manage.auth0.com) and make sure that `Application Type` is set to `Single Page Application` and `Token Endpoint Authentication Method` is set to `None` (**Note:** there is a known issue with the Auth0 "Default App", if you are unable to set `Token Endpoint Authentication Method` to `None`, create a new Application of type `Single Page Application` or see the advice in [issues/93](https://github.com/auth0/auth0-react/issues/93#issuecomment-673431605)) 23 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | @Library('k8sAgents') agentLibrary 2 | @Library('auth0') _ 3 | SDKDeployment() 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Auth0 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Auth0 SDK for React Single Page Applications](https://cdn.auth0.com/website/sdks/banners/auth0-react-banner.png) 2 | 3 | [![npm](https://img.shields.io/npm/v/@auth0/auth0-react.svg?style=flat)](https://www.npmjs.com/package/@auth0/auth0-react) 4 | [![codecov](https://img.shields.io/codecov/c/github/auth0/auth0-react/main.svg?style=flat)](https://codecov.io/gh/auth0/auth0-react) 5 | ![Downloads](https://img.shields.io/npm/dw/@auth0/auth0-react) 6 | [![License](https://img.shields.io/:license-mit-blue.svg?style=flat)](https://opensource.org/licenses/MIT) 7 | [![CircleCI](https://img.shields.io/circleci/build/github/auth0/auth0-react.svg?branch=main&style=flat)](https://circleci.com/gh/auth0/auth0-react) 8 | 9 | 📚 [Documentation](#documentation) - 🚀 [Getting Started](#getting-started) - 💻 [API Reference](#api-reference) - 💬 [Feedback](#feedback) 10 | 11 | ## Documentation 12 | 13 | - [Quickstart](https://auth0.com/docs/quickstart/spa/react) - our interactive guide for quickly adding login, logout and user information to a React app using Auth0. 14 | - [Sample App](https://github.com/auth0-samples/auth0-react-samples/tree/master/Sample-01) - a full-fledged React application integrated with Auth0. 15 | - [FAQs](https://github.com/auth0/auth0-react/blob/main/FAQ.md) - frequently asked questions about the auth0-react SDK. 16 | - [Examples](https://github.com/auth0/auth0-react/blob/main/EXAMPLES.md) - code samples for common React authentication scenario's. 17 | - [Docs site](https://www.auth0.com/docs) - explore our docs site and learn more about Auth0. 18 | 19 | ## Getting started 20 | 21 | ### Installation 22 | 23 | Using [npm](https://npmjs.org/) 24 | 25 | ```bash 26 | npm install @auth0/auth0-react 27 | ``` 28 | 29 | Using [yarn](https://yarnpkg.com/) 30 | 31 | ```bash 32 | yarn add @auth0/auth0-react 33 | ``` 34 | 35 | ### Configure Auth0 36 | 37 | Create a **Single Page Application** in the [Auth0 Dashboard](https://manage.auth0.com/#/applications). 38 | 39 | > **If you're using an existing application**, verify that you have configured the following settings in your Single Page Application: 40 | > 41 | > - Click on the "Settings" tab of your application's page. 42 | > - Scroll down and click on the "Show Advanced Settings" link. 43 | > - Under "Advanced Settings", click on the "OAuth" tab. 44 | > - Ensure that "JsonWebToken Signature Algorithm" is set to `RS256` and that "OIDC Conformant" is enabled. 45 | 46 | Next, configure the following URLs for your application under the "Application URIs" section of the "Settings" page: 47 | 48 | - **Allowed Callback URLs**: `http://localhost:3000` 49 | - **Allowed Logout URLs**: `http://localhost:3000` 50 | - **Allowed Web Origins**: `http://localhost:3000` 51 | 52 | > These URLs should reflect the origins that your application is running on. **Allowed Callback URLs** may also include a path, depending on where you're handling the callback. 53 | 54 | Take note of the **Client ID** and **Domain** values under the "Basic Information" section. You'll need these values in the next step. 55 | 56 | ### Configure the SDK 57 | 58 | Configure the SDK by wrapping your application in `Auth0Provider`: 59 | 60 | ```jsx 61 | // src/index.js 62 | import React from 'react'; 63 | import { createRoot } from 'react-dom/client'; 64 | import { Auth0Provider } from '@auth0/auth0-react'; 65 | import App from './App'; 66 | 67 | const root = createRoot(document.getElementById('app')); 68 | 69 | root.render( 70 | 77 | 78 | 79 | ); 80 | ``` 81 | 82 |
83 | Instructions for React <18 84 |
85 | 86 | ```jsx 87 | // src/index.js 88 | import React from 'react'; 89 | import ReactDOM from 'react-dom'; 90 | import { Auth0Provider } from '@auth0/auth0-react'; 91 | import App from './App'; 92 | 93 | ReactDOM.render( 94 | 101 | 102 | , 103 | document.getElementById('app') 104 | ); 105 | ``` 106 |
107 | 108 | Use the `useAuth0` hook in your components to access authentication state (`isLoading`, `isAuthenticated` and `user`) and authentication methods (`loginWithRedirect` and `logout`): 109 | 110 | ```jsx 111 | // src/App.js 112 | import React from 'react'; 113 | import { useAuth0 } from '@auth0/auth0-react'; 114 | 115 | function App() { 116 | const { isLoading, isAuthenticated, error, user, loginWithRedirect, logout } = 117 | useAuth0(); 118 | 119 | if (isLoading) { 120 | return
Loading...
; 121 | } 122 | if (error) { 123 | return
Oops... {error.message}
; 124 | } 125 | 126 | if (isAuthenticated) { 127 | return ( 128 |
129 | Hello {user.name}{' '} 130 | 133 |
134 | ); 135 | } else { 136 | return ; 137 | } 138 | } 139 | 140 | export default App; 141 | ``` 142 | 143 | For more code samples on how to integrate **auth0-react** SDK in your **React** application, have a look at our [examples](https://github.com/auth0/auth0-react/blob/main/EXAMPLES.md). 144 | 145 | ## API reference 146 | 147 | Explore public API's available in auth0-react. 148 | 149 | - [Auth0Provider](https://auth0.github.io/auth0-react/functions/Auth0Provider.html) 150 | - [Auth0ProviderOptions](https://auth0.github.io/auth0-react/interfaces/Auth0ProviderOptions.html) 151 | - [useAuth0](https://auth0.github.io/auth0-react/functions/useAuth0.html) 152 | - [withAuth0](https://auth0.github.io/auth0-react/functions/withAuth0.html) 153 | - [withAuthenticationRequired](https://auth0.github.io/auth0-react/functions/withAuthenticationRequired.html) 154 | 155 | ## Feedback 156 | 157 | ### Contributing 158 | 159 | We appreciate feedback and contribution to this repo! Before you get started, please see the following: 160 | 161 | - [Auth0's general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md) 162 | - [Auth0's code of conduct guidelines](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md) 163 | - [This repo's contribution guide](https://github.com/auth0/auth0-react/blob/main/CONTRIBUTING.md) 164 | 165 | ### Raise an issue 166 | 167 | To provide feedback or report a bug, please [raise an issue on our issue tracker](https://github.com/auth0/auth0-react/issues). 168 | 169 | ### Vulnerability Reporting 170 | 171 | Please do not report security vulnerabilities on the public GitHub issue tracker. The [Responsible Disclosure Program](https://auth0.com/responsible-disclosure-policy) details the procedure for disclosing security issues. 172 | 173 | --- 174 | 175 |

176 | 177 | 178 | 179 | Auth0 Logo 180 | 181 |

182 |

Auth0 is an easy to implement, adaptable authentication and authorization platform. To learn more checkout Why Auth0?

183 |

184 | This project is licensed under the MIT license. See the LICENSE file for more info.

185 | -------------------------------------------------------------------------------- /TROUBLESHOOTING.md: -------------------------------------------------------------------------------- 1 | # Troubleshooting 2 | 3 | When your application is not behaving as expected: 4 | 5 | - Check for any messages in the console 6 | - Check the Network Activity especially any requests to your authorization server 7 | - Check the log data in your [Auth0 Dashboard](https://manage.auth0.com#/logs) 8 | - Check the `@auth0/auth0-spa-js` [FAQs](https://github.com/auth0/auth0-spa-js/blob/main/FAQ.md) 9 | 10 | If you believe there is a bug in the SDK, [raise an issue](https://github.com/auth0/auth0-spa-js/issues/new/choose). Be sure to include all the information required to reproduce the issue. 11 | -------------------------------------------------------------------------------- /__mocks__/@auth0/auth0-spa-js.tsx: -------------------------------------------------------------------------------- 1 | const handleRedirectCallback = jest.fn(() => ({ appState: {} })); 2 | const buildLogoutUrl = jest.fn(); 3 | const buildAuthorizeUrl = jest.fn(); 4 | const checkSession = jest.fn(); 5 | const getTokenSilently = jest.fn(); 6 | const getTokenWithPopup = jest.fn(); 7 | const getUser = jest.fn(); 8 | const getIdTokenClaims = jest.fn(); 9 | const isAuthenticated = jest.fn(() => false); 10 | const loginWithPopup = jest.fn(); 11 | const loginWithRedirect = jest.fn(); 12 | const logout = jest.fn(); 13 | 14 | export const Auth0Client = jest.fn(() => { 15 | return { 16 | buildAuthorizeUrl, 17 | buildLogoutUrl, 18 | checkSession, 19 | handleRedirectCallback, 20 | getTokenSilently, 21 | getTokenWithPopup, 22 | getUser, 23 | getIdTokenClaims, 24 | isAuthenticated, 25 | loginWithPopup, 26 | loginWithRedirect, 27 | logout, 28 | }; 29 | }); 30 | -------------------------------------------------------------------------------- /__tests__/auth-reducer.test.tsx: -------------------------------------------------------------------------------- 1 | import { reducer } from '../src/reducer'; 2 | import { initialAuthState } from '../src/auth-state'; 3 | 4 | describe('reducer', () => { 5 | it('should initialise when authenticated', async () => { 6 | const payload = { 7 | isAuthenticated: true, 8 | user: { name: 'Bob' }, 9 | }; 10 | expect( 11 | reducer(initialAuthState, { type: 'INITIALISED', ...payload }) 12 | ).toEqual({ 13 | ...initialAuthState, 14 | isLoading: false, 15 | ...payload, 16 | }); 17 | }); 18 | 19 | it('should initialise when not authenticated', async () => { 20 | const payload = { 21 | isAuthenticated: false, 22 | }; 23 | expect( 24 | reducer(initialAuthState, { type: 'INITIALISED', ...payload }) 25 | ).toEqual({ 26 | ...initialAuthState, 27 | isLoading: false, 28 | ...payload, 29 | }); 30 | }); 31 | 32 | it('should handle error state', async () => { 33 | const payload = { 34 | error: new Error('__test_error__'), 35 | }; 36 | expect(reducer(initialAuthState, { type: 'ERROR', ...payload })).toEqual({ 37 | ...initialAuthState, 38 | isLoading: false, 39 | ...payload, 40 | }); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /__tests__/errors.test.tsx: -------------------------------------------------------------------------------- 1 | import { OAuthError } from '../src'; 2 | 3 | describe('OAuthError', () => { 4 | it('should produce an OAuth JS error with error_description properties', async () => { 5 | const error = new OAuthError( 6 | '__test_error__', 7 | '__test_error_description__' 8 | ); 9 | expect(error.error).toBe('__test_error__'); 10 | expect(error.error_description).toBe('__test_error_description__'); 11 | expect(error.message).toBe('__test_error_description__'); 12 | }); 13 | 14 | it('should produce an OAuth JS error with error properties', async () => { 15 | const error = new OAuthError('__test_error__'); 16 | expect(error.error).toBe('__test_error__'); 17 | expect(error.message).toBe('__test_error__'); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /__tests__/helpers.tsx: -------------------------------------------------------------------------------- 1 | import React, { PropsWithChildren } from 'react'; 2 | import Auth0Provider, { Auth0ProviderOptions } from '../src/auth0-provider'; 3 | 4 | export const createWrapper = ({ 5 | clientId = '__test_client_id__', 6 | domain = '__test_domain__', 7 | ...opts 8 | }: Partial = {}) => { 9 | return function Wrapper({ 10 | children, 11 | }: PropsWithChildren>): React.JSX.Element { 12 | return ( 13 | 14 | {children} 15 | 16 | ); 17 | }; 18 | }; 19 | 20 | export interface Defer { 21 | resolve: (value: TData | PromiseLike) => void; 22 | reject: (reason?: unknown) => void; 23 | promise: Promise; 24 | } 25 | 26 | export function defer() { 27 | const deferred: Defer = {} as unknown as Defer; 28 | 29 | const promise = new Promise(function (resolve, reject) { 30 | deferred.resolve = resolve; 31 | deferred.reject = reject; 32 | }); 33 | 34 | deferred.promise = promise; 35 | return deferred; 36 | } 37 | -------------------------------------------------------------------------------- /__tests__/ssr.test.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @jest-environment node 3 | */ 4 | import React from 'react'; 5 | import ReactDOMServer from 'react-dom/server'; 6 | import { Auth0Provider, Auth0Context } from '../src'; 7 | 8 | jest.unmock('@auth0/auth0-spa-js'); 9 | 10 | describe('In a Node SSR environment', () => { 11 | it('auth state is initialised', async () => { 12 | let isLoading, isAuthenticated, user, loginWithRedirect; 13 | ReactDOMServer.renderToString( 14 | 15 | 16 | {(value): React.JSX.Element => { 17 | ({ isLoading, isAuthenticated, user, loginWithRedirect } = value); 18 | return
App
; 19 | }} 20 |
21 |
22 | ); 23 | expect(isLoading).toBeTruthy(); 24 | expect(isAuthenticated).toBeFalsy(); 25 | expect(user).toBeUndefined(); 26 | await expect(loginWithRedirect).rejects.toThrowError( 27 | 'window is not defined' 28 | ); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /__tests__/use-auth.test.tsx: -------------------------------------------------------------------------------- 1 | import { act, renderHook, waitFor } from '@testing-library/react'; 2 | import React from 'react'; 3 | import { Auth0ContextInterface, initialContext } from '../src/auth0-context'; 4 | import useAuth0 from '../src/use-auth0'; 5 | import { createWrapper } from './helpers'; 6 | 7 | describe('useAuth0', () => { 8 | it('should provide the auth context', async () => { 9 | const wrapper = createWrapper(); 10 | const { 11 | result: { current } 12 | } = renderHook(() => useAuth0(), { wrapper }); 13 | await waitFor(() => { 14 | expect(current).toBeDefined(); 15 | }); 16 | }); 17 | 18 | it('should throw with no provider', () => { 19 | const { 20 | result: { current }, 21 | } = renderHook(() => useAuth0()); 22 | expect(current.loginWithRedirect).toThrowError( 23 | 'You forgot to wrap your component in .' 24 | ); 25 | }); 26 | 27 | it('should throw when context is not associated with provider', async () => { 28 | const context = React.createContext(initialContext); 29 | const wrapper = createWrapper({ context }); 30 | const { 31 | result: { current }, 32 | } = renderHook(() => useAuth0(), { wrapper }); 33 | await act(async () => { 34 | expect(current.loginWithRedirect).toThrowError( 35 | 'You forgot to wrap your component in .' 36 | ); 37 | }); 38 | }); 39 | 40 | it('should accept custom auth context', async () => { 41 | const context = React.createContext(initialContext); 42 | const wrapper = createWrapper({ context }); 43 | const { 44 | result: { current }, 45 | } = renderHook(() => useAuth0(context), { wrapper }); 46 | await waitFor(() => { 47 | expect(current).toBeDefined(); 48 | expect(current.loginWithRedirect).not.toThrowError(); 49 | }); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /__tests__/utils.test.tsx: -------------------------------------------------------------------------------- 1 | import { hasAuthParams, loginError, tokenError } from '../src/utils'; 2 | import { OAuthError } from '../src/errors'; 3 | 4 | describe('utils hasAuthParams', () => { 5 | it('should not recognise only the code param', async () => { 6 | ['?code=1', '?foo=1&code=2', '?code=1&foo=2'].forEach((search) => 7 | expect(hasAuthParams(search)).toBeFalsy() 8 | ); 9 | }); 10 | 11 | it('should recognise the code and state param', async () => { 12 | [ 13 | '?code=1&state=2', 14 | '?foo=1&state=2&code=3', 15 | '?code=1&foo=2&state=3', 16 | '?state=1&code=2&foo=3', 17 | ].forEach((search) => expect(hasAuthParams(search)).toBeTruthy()); 18 | }); 19 | 20 | it('should recognise the error and state param', async () => { 21 | [ 22 | '?error=1&state=2', 23 | '?foo=1&state=2&error=3', 24 | '?error=1&foo=2&state=3', 25 | '?state=1&error=2&foo=3', 26 | ].forEach((search) => expect(hasAuthParams(search)).toBeTruthy()); 27 | }); 28 | 29 | it('should ignore the error param without state param', async () => { 30 | ['?error=1', '?foo=1&error=2', '?error=1&foo=2'].forEach((search) => 31 | expect(hasAuthParams(search)).toBeFalsy() 32 | ); 33 | }); 34 | 35 | it('should ignore invalid params', async () => { 36 | ['', '?', '?foo=1', '?code=&foo=2', '?error='].forEach((search) => 37 | expect(hasAuthParams(search)).toBeFalsy() 38 | ); 39 | }); 40 | }); 41 | 42 | describe('utils error', () => { 43 | it('should return the original error', async () => { 44 | const error = new Error('__test_error__'); 45 | expect(loginError(error)).toBe(error); 46 | }); 47 | 48 | it('should convert OAuth error data to an OAuth JS error', async () => { 49 | const error = { 50 | error: '__test_error__', 51 | error_description: '__test_error_description__', 52 | }; 53 | expect(() => { 54 | throw tokenError(error); 55 | }).toThrow(OAuthError); 56 | }); 57 | 58 | it('should convert a ProgressEvent error to a JS error', async () => { 59 | const error = new ProgressEvent('error'); 60 | expect(() => { 61 | throw loginError(error); 62 | }).toThrowError('Login failed'); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /__tests__/with-auth0.test.tsx: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom'; 2 | import { render, screen } from '@testing-library/react'; 3 | import React, { Component } from 'react'; 4 | import { Auth0ContextInterface, initialContext } from '../src/auth0-context'; 5 | import withAuth0, { WithAuth0Props } from '../src/with-auth0'; 6 | 7 | describe('withAuth0', () => { 8 | it('should wrap a class component', () => { 9 | class MyComponent extends Component { 10 | render() { 11 | return <>hasAuth: {`${!!this.props.auth0}`}; 12 | } 13 | } 14 | const WrappedComponent = withAuth0(MyComponent); 15 | render(); 16 | expect(screen.getByText('hasAuth: true')).toBeInTheDocument(); 17 | }); 18 | 19 | it('should wrap a class component and provide context', () => { 20 | const context = React.createContext(initialContext); 21 | class MyComponent extends Component { 22 | render() { 23 | return <>hasAuth: {`${!!this.props.auth0}`}; 24 | } 25 | } 26 | const WrappedComponent = withAuth0(MyComponent, context); 27 | render(); 28 | expect(screen.getByText('hasAuth: true')).toBeInTheDocument(); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /browserstack.json: -------------------------------------------------------------------------------- 1 | { 2 | "browsers": [ 3 | { 4 | "browser": "chrome", 5 | "os": "Windows 10", 6 | "versions": ["latest"] 7 | }, 8 | { 9 | "browser": "firefox", 10 | "os": "Windows 10", 11 | "versions": ["latest"] 12 | }, 13 | { 14 | "browser": "edge", 15 | "os": "Windows 10", 16 | "versions": ["latest"] 17 | } 18 | ], 19 | "run_settings": { 20 | "cypress_config_file": "./cypress-bs.config.js", 21 | "cypress-version": "13.1", 22 | "project_name": "Auth0 React SDK", 23 | "exclude": [], 24 | "parallels": "5", 25 | "npm_dependencies": { 26 | "typescript": "^4.6.3" 27 | }, 28 | "package_config_options": {}, 29 | "headless": true 30 | }, 31 | "connection_settings": { 32 | "local": true, 33 | "local_mode": "always-on" 34 | }, 35 | "disable_usage_reporting": false 36 | } 37 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | -------------------------------------------------------------------------------- /cypress-bs.config.js: -------------------------------------------------------------------------------- 1 | const { defineConfig } = require('cypress'); 2 | 3 | module.exports = defineConfig({ 4 | defaultCommandTimeout: 7500, 5 | chromeWebSecurity: false, 6 | viewportWidth: 1000, 7 | viewportHeight: 1000, 8 | fixturesFolder: false, 9 | reporter: 'junit', 10 | reporterOptions: { 11 | mochaFile: 'test-results/cypress/junit-[hash].xml', 12 | }, 13 | e2e: { 14 | setupNodeEvents(on, config) {}, 15 | baseUrl: 'http://127.0.0.1:3000', 16 | supportFile: false, 17 | }, 18 | }); 19 | -------------------------------------------------------------------------------- /cypress.config.js: -------------------------------------------------------------------------------- 1 | const { defineConfig } = require('cypress'); 2 | 3 | module.exports = defineConfig({ 4 | defaultCommandTimeout: 7500, 5 | chromeWebSecurity: false, 6 | viewportWidth: 1000, 7 | viewportHeight: 1000, 8 | fixturesFolder: false, 9 | reporter: 'junit', 10 | reporterOptions: { 11 | mochaFile: 'test-results/cypress/junit-[hash].xml', 12 | }, 13 | e2e: { 14 | setupNodeEvents(on, config) {}, 15 | baseUrl: 'http://localhost:3000', 16 | supportFile: false, 17 | }, 18 | }); 19 | -------------------------------------------------------------------------------- /cypress/e2e/smoke-bs.cy.ts: -------------------------------------------------------------------------------- 1 | const EMAIL = 'test'; 2 | const PASSWORD = 'test'; 3 | 4 | if (!EMAIL || !PASSWORD) { 5 | throw new Error( 6 | 'You must provide CYPRESS_USER_EMAIL and CYPRESS_USER_PASSWORD environment variables' 7 | ); 8 | } 9 | 10 | const loginToNodeOidc = (): void => { 11 | cy.get('input[name=login]').clear().type(EMAIL); 12 | cy.get('input[name=password]').clear().type(PASSWORD); 13 | cy.get('.login-submit').click(); 14 | cy.get('.login-submit').click(); 15 | }; 16 | 17 | const login = (): void => { 18 | return loginToNodeOidc(); 19 | }; 20 | 21 | const fixCookies = () => { 22 | // Temporary fix for https://github.com/cypress-io/cypress/issues/6375 23 | if (Cypress.isBrowser('firefox')) { 24 | cy.getCookies({ log: false }).then((cookies) => 25 | cookies.forEach((cookie) => cy.clearCookie(cookie.name, { log: false })) 26 | ); 27 | cy.log('clearCookies'); 28 | } else { 29 | cy.clearCookies(); 30 | } 31 | }; 32 | 33 | describe('Smoke tests', () => { 34 | afterEach(fixCookies); 35 | 36 | it('do basic login and show user', () => { 37 | cy.visit('/'); 38 | 39 | cy.get('[data-cy=use-node-oidc-provider]').click(); 40 | cy.get('#login').click(); 41 | 42 | login(); 43 | 44 | cy.get('#hello').contains(`Hello, ${EMAIL}!`); 45 | cy.get('#logout').click(); 46 | cy.get('button[name=logout]').click(); 47 | cy.get('#login').should('exist'); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /cypress/e2e/smoke.cy.ts: -------------------------------------------------------------------------------- 1 | const EMAIL = Cypress.env('USER_EMAIL'); 2 | const PASSWORD = Cypress.env('USER_PASSWORD'); 3 | 4 | if (!EMAIL || !PASSWORD) { 5 | throw new Error( 6 | 'You must provide CYPRESS_USER_EMAIL and CYPRESS_USER_PASSWORD environment variables' 7 | ); 8 | } 9 | 10 | const loginToAuth0 = (): void => { 11 | cy.get('.auth0-lock-input-username .auth0-lock-input').clear().type(EMAIL); 12 | cy.get('.auth0-lock-input-password .auth0-lock-input').clear().type(PASSWORD); 13 | cy.get('.auth0-lock-submit').click(); 14 | }; 15 | 16 | describe('Smoke tests', () => { 17 | it('do basic login and show user', () => { 18 | cy.visit('/'); 19 | cy.get('#login').should('be.visible'); 20 | cy.get('#login').click(); 21 | 22 | loginToAuth0(); 23 | 24 | cy.get('#hello').contains(`Hello, ${EMAIL}!`); 25 | cy.get('#logout').click(); 26 | cy.get('#login').should('exist'); 27 | }); 28 | 29 | it('should protect a route and return to path after login', () => { 30 | cy.visit('/users'); 31 | 32 | loginToAuth0(); 33 | 34 | // Make sure the table has rendered with data as that is when the page has loaded completely 35 | // and there shouldn't be any issues with the logout button being recreated 36 | cy.get('table tbody tr').should('have.length', 2); 37 | cy.url().should('include', '/users'); 38 | cy.get('#logout').click(); 39 | }); 40 | 41 | it('should access an api', () => { 42 | cy.visit('/users'); 43 | 44 | loginToAuth0(); 45 | 46 | // Make sure the table has rendered with data as that is when the page has loaded completely 47 | // and there shouldn't be any issues with the logout button being recreated 48 | cy.get('table tbody tr').should('have.length', 2); 49 | cy.get('table').contains('bob@example.com'); 50 | cy.get('#logout').click(); 51 | }); 52 | }); 53 | -------------------------------------------------------------------------------- /cypress/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "baseUrl": "../node_modules", 5 | "target": "es5", 6 | "lib": ["es5", "dom"], 7 | "types": ["cypress"] 8 | }, 9 | "include": ["**/*.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- 1 | TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. -------------------------------------------------------------------------------- /docs/assets/highlight.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --light-hl-0: #795E26; 3 | --dark-hl-0: #DCDCAA; 4 | --light-hl-1: #000000; 5 | --dark-hl-1: #D4D4D4; 6 | --light-hl-2: #A31515; 7 | --dark-hl-2: #CE9178; 8 | --light-hl-3: #008000; 9 | --dark-hl-3: #6A9955; 10 | --light-hl-4: #AF00DB; 11 | --dark-hl-4: #C586C0; 12 | --light-hl-5: #001080; 13 | --dark-hl-5: #9CDCFE; 14 | --light-hl-6: #0000FF; 15 | --dark-hl-6: #569CD6; 16 | --light-hl-7: #0070C1; 17 | --dark-hl-7: #4FC1FF; 18 | --light-hl-8: #800000; 19 | --dark-hl-8: #808080; 20 | --light-hl-9: #267F99; 21 | --dark-hl-9: #4EC9B0; 22 | --light-hl-10: #E50000; 23 | --dark-hl-10: #9CDCFE; 24 | --light-hl-11: #000000FF; 25 | --dark-hl-11: #D4D4D4; 26 | --light-hl-12: #800000; 27 | --dark-hl-12: #569CD6; 28 | --light-hl-13: #098658; 29 | --dark-hl-13: #B5CEA8; 30 | --light-code-background: #FFFFFF; 31 | --dark-code-background: #1E1E1E; 32 | } 33 | 34 | @media (prefers-color-scheme: light) { :root { 35 | --hl-0: var(--light-hl-0); 36 | --hl-1: var(--light-hl-1); 37 | --hl-2: var(--light-hl-2); 38 | --hl-3: var(--light-hl-3); 39 | --hl-4: var(--light-hl-4); 40 | --hl-5: var(--light-hl-5); 41 | --hl-6: var(--light-hl-6); 42 | --hl-7: var(--light-hl-7); 43 | --hl-8: var(--light-hl-8); 44 | --hl-9: var(--light-hl-9); 45 | --hl-10: var(--light-hl-10); 46 | --hl-11: var(--light-hl-11); 47 | --hl-12: var(--light-hl-12); 48 | --hl-13: var(--light-hl-13); 49 | --code-background: var(--light-code-background); 50 | } } 51 | 52 | @media (prefers-color-scheme: dark) { :root { 53 | --hl-0: var(--dark-hl-0); 54 | --hl-1: var(--dark-hl-1); 55 | --hl-2: var(--dark-hl-2); 56 | --hl-3: var(--dark-hl-3); 57 | --hl-4: var(--dark-hl-4); 58 | --hl-5: var(--dark-hl-5); 59 | --hl-6: var(--dark-hl-6); 60 | --hl-7: var(--dark-hl-7); 61 | --hl-8: var(--dark-hl-8); 62 | --hl-9: var(--dark-hl-9); 63 | --hl-10: var(--dark-hl-10); 64 | --hl-11: var(--dark-hl-11); 65 | --hl-12: var(--dark-hl-12); 66 | --hl-13: var(--dark-hl-13); 67 | --code-background: var(--dark-code-background); 68 | } } 69 | 70 | :root[data-theme='light'] { 71 | --hl-0: var(--light-hl-0); 72 | --hl-1: var(--light-hl-1); 73 | --hl-2: var(--light-hl-2); 74 | --hl-3: var(--light-hl-3); 75 | --hl-4: var(--light-hl-4); 76 | --hl-5: var(--light-hl-5); 77 | --hl-6: var(--light-hl-6); 78 | --hl-7: var(--light-hl-7); 79 | --hl-8: var(--light-hl-8); 80 | --hl-9: var(--light-hl-9); 81 | --hl-10: var(--light-hl-10); 82 | --hl-11: var(--light-hl-11); 83 | --hl-12: var(--light-hl-12); 84 | --hl-13: var(--light-hl-13); 85 | --code-background: var(--light-code-background); 86 | } 87 | 88 | :root[data-theme='dark'] { 89 | --hl-0: var(--dark-hl-0); 90 | --hl-1: var(--dark-hl-1); 91 | --hl-2: var(--dark-hl-2); 92 | --hl-3: var(--dark-hl-3); 93 | --hl-4: var(--dark-hl-4); 94 | --hl-5: var(--dark-hl-5); 95 | --hl-6: var(--dark-hl-6); 96 | --hl-7: var(--dark-hl-7); 97 | --hl-8: var(--dark-hl-8); 98 | --hl-9: var(--dark-hl-9); 99 | --hl-10: var(--dark-hl-10); 100 | --hl-11: var(--dark-hl-11); 101 | --hl-12: var(--dark-hl-12); 102 | --hl-13: var(--dark-hl-13); 103 | --code-background: var(--dark-code-background); 104 | } 105 | 106 | .hl-0 { color: var(--hl-0); } 107 | .hl-1 { color: var(--hl-1); } 108 | .hl-2 { color: var(--hl-2); } 109 | .hl-3 { color: var(--hl-3); } 110 | .hl-4 { color: var(--hl-4); } 111 | .hl-5 { color: var(--hl-5); } 112 | .hl-6 { color: var(--hl-6); } 113 | .hl-7 { color: var(--hl-7); } 114 | .hl-8 { color: var(--hl-8); } 115 | .hl-9 { color: var(--hl-9); } 116 | .hl-10 { color: var(--hl-10); } 117 | .hl-11 { color: var(--hl-11); } 118 | .hl-12 { color: var(--hl-12); } 119 | .hl-13 { color: var(--hl-13); } 120 | pre, code { background: var(--code-background); } 121 | -------------------------------------------------------------------------------- /docs/assets/navigation.js: -------------------------------------------------------------------------------- 1 | window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAE6WWXW+bMBSG/4uv062N1q7L3RRNU6RUjZJWu5h24cIBrDo2sw9b06r/fTKMBPAHyLkM5/XzOMY+5ucbQXhBsiBfKyxAIEsoMim+KSUVmZGSYkEWJOFUa9AfHaEPBe45mZFnJlKyuJrfzpo0WRDU6QXTF/CCoATl5H12tH0HAYolHk23GsdfiTvYS3VY0qQAW9ArxxnWMqF8h1LRHDwWKxJnusvoFn5XTEHqWa9hItLDtGYi30KmQBcP8hl828CXjPPem13lMZ1qFrtD2MiyKpdUJMC5d5Ecobj51qAHtgdZYcjVjcSZwpLz+Y8aHFzzNI5nXtblUgrzcyUQVEaTzrlg7aOmkVjJvnR+fTNEb5T8w1JQ96VpP9pPHgTHwFKx17qjbaiiez93kLOwE1sf1idmxzgI5IfQn/FkzxP/YFjUG3SKeRiOU68GHbIjWjk642RsWs/RzW1qceC1zGWFofXpJUL7qwk+Kj5OO4XiZt10OCkylodkduwM3VrmTIzauqk42RZSpiDBUZ8rGHo/ZoO3PaN0I/uRKbDTN1J7L4emPDoq2L/KcocUO4cLD6XpV/+fD8Zefvl8dT3vjK+Pn/lSMaYhpFd0kia9vBpDn7g1yWMhnt29SU74rBJJvXS9m6Zvufnku1+8nDYQAFUa6qiL0dYCw/+2e801/licALA3U4hopy3Fr3+FU0zaLAwAAA==" -------------------------------------------------------------------------------- /docs/assets/search.js: -------------------------------------------------------------------------------- 1 | window.searchData = "data:application/octet-stream;base64,H4sIAAAAAAAAE81ayW7bSBD9l9aVltWLqOWWCeYQIECCJJg5EIbBUG2bME1ySCoLDP/7oLlWUV1cpATOSbBZVf36vdfNYpPPLEu+52zvPbPHMD6wvascFvtPmu3Zm2PxsPqYJd/Cg86Yw45ZxPbs7hgHRZjE+TW6vnwoniLmsCDy81znbM/Yi9MUFWvXXvVDWpZqi4dxobM7P9C96nXc4CB8JTrswUMYHTIdz6q8AFlgCIelfqbjggJPQEjiT/oQZjoo3vpR9NUPHueBseafBctdr2UnwO1t8TPVl2JZVmWu1CxQS8ukCPryxzC9jECiwuXKBklc6B/FTG+1SWcBEKvdhq9Ft4zS9HPhF52ORo38uvn34EoZ9IOlzqINIaA3WAi+Ml0cs/hLMmGMJYgdHqw2IJxWN+Ix1yWfll2ruTTMUFfqe1g8ULXaa5N3v3+bjI9Zklr3PRwxfcfzEcbhgosm2E5xD+QgLTouwsA3dHzS/x3DTB8GeDoNnk3caYmBe8ho0nR6Tzw8e5jFqLXH5zh6qwnj+wsQ9utcDnPqreccgM0tSJyPdIlnTNL7l75LMo1LXTQNouAfSLgN6XLkhjCFdysDhABRch/GF6/zRa/ML16EA13BRHxjLcIsH/T6+Lc9dL02vr48r4uvk941EyUbon7g9G33XhdvgkDn+ZfkUcefw0jHRfRz3kALsshAJ3YytzPb6TmIxpaVvSAxu0mEGkd9TNJjehF+WOUPobSFNPE5ZYTVboY0re8OZejbyA+f6CdaEnw//TWJRFgaBt35DOI5DW3uhuDmTjwTry3/1cg7AdOwx+kuxV7udFpj/J2zkE+SX585tGw5/ZQyQtvgco2S++R4htGqpNfkKDl2lpq7p9UTIDh58ONDpCcfudgRkkVejTM7oobD7UwKifkRlOosS7KZeJucDlWRH67C/CqMH3QWFuUD9mQCEZwwB90jeFCfBuw0+7dAfJ/4B+IpdhBcl/cbYB1zPVfHOuXXgIGt9/tyFQ88DaGAyR194+n3I89atrjhfl5s20E+mIn+jVZFnXPdXRqstuYCPnHlRXYMivFyCxxrX/IA3aQFTY11uoTPGOX2oPMgC1N01DA4Yi9jfPQbh4XxQf9g+2f2TWe5ydszsZTLHXPYXaijg3k1VMFyWJA8PZkiN/W1f7Rh00RUIdcr5ngrR66XK9e9uXG8JqO8UP6jDOPM8bgtjKMwwRxP2MIECpPM8aQtTKIwxRxPOVwt3d0GhSkUtmaOt7ZVW6Mwlzme64jdcrfG1VwUtmGOt7FV26CwLYVti8J2zPG2tkF3mF7D9s7Kb0+HUgirYBxLYZpXj9s1w2pwwzq3ysaxIKZ78bhVOY414YZ7rqyRWBbuUhRxLAw3AnCr0Bxrw0lxOFaHGxW4ay2JBRIrqqTAAolSIKuBRG+tCMqQAusjSn221pJYH1HqY/WRwPoII4Kw+khgfYRLzhzrI4wIwmo4gfURpD4C6yOMCMK+oWB9JKmPxPpII4Kwbz5YHynIkr3dzIggrF6XWB9J7mgSyyNLeaxel1geScojsTyylMfqdYnlkaQ8EssjS3k2NgtLLI8yIgirhRXWR5X6WC2ssD7KqCCtFlZYIFXeb6zOVL07jpFBWg2nsELKyCCtPlJYIWV0kFZ7KCyR2pB8KiyRMkJIqz9UpVHZJ3zTWaEP76p+wfPah7Fndls3EW0D88wU2z+/OGxb/fD6V6zqX7f+rf8v6/9LUf/W6bKOk2XcS9eBmL8MTj9N8+oleIdi06HYUGnV288up+spnxmXQ1ntET1I3nbJYkpy20yjKjtQRQ1VSdsvcrrsVZe8mpKbNP09AAAoIEp0n8d0aYA5QaXB1rvLlNAvLp3b59vt0hofUSPXjThAC9whd1W2omxiaaoB+jVAT/nzXhd+eYhcmGPQvH3xAAAB5cR6UhnzMj2tTutAHSCfoCZ0r4vwUNYI6lNmUAAKuSMKVKcfWf0EGLSnO6AMUEdSOMLcxycJIB8sJkVZOcyj5mEfZIIFpCgHl6eDNvMDX4jBZDv7wMqS2gLa9Kw9pwYVJKgwAKA8gARpwIWSsk+VZpm1BKZRFOyk1Kq/kCTAq6iBk/hr+ZLX773mBrwDu3DKdUk85DhI3GiBnmc4oI9Tbm1yKe9IsHIUtXNX334UCUwEVq+3Ik5tg+ZTtiESwDwoMY65PrnvgSXDqcVWnWOB6YIdS1Ebr7H56V0WZHLK421mWn0gBdLhHWps4M5uWftZEigFTMMpyehStg0E7ADcKsGNw9Iw1VEYa7b3bl5e/gfBQ3fmeysAAA=="; -------------------------------------------------------------------------------- /docs/classes/InMemoryCache.html: -------------------------------------------------------------------------------- 1 | InMemoryCache | @auth0/auth0-react

Constructors

Properties

Constructors

Properties

enclosedCache: ICache
-------------------------------------------------------------------------------- /docs/functions/Auth0Provider.html: -------------------------------------------------------------------------------- 1 | Auth0Provider | @auth0/auth0-react

Function Auth0Provider

  • <Auth0Provider
    domain={domain}
    clientId={clientId}
    authorizationParams={{ redirect_uri: window.location.origin }}>
    <MyApp />
    </Auth0Provider> 2 |
    3 |

    Provides the Auth0Context to its child components.

    4 |

    Parameters

    Returns Element

-------------------------------------------------------------------------------- /docs/functions/withAuthenticationRequired.html: -------------------------------------------------------------------------------- 1 | withAuthenticationRequired | @auth0/auth0-react

Function withAuthenticationRequired

  • const MyProtectedComponent = withAuthenticationRequired(MyComponent);
    2 | 
    3 |

    When you wrap your components in this Higher Order Component and an anonymous user visits your component 4 | they will be redirected to the login page; after login they will be returned to the page they were redirected from.

    5 |

    Type Parameters

    • P extends object

    Parameters

    Returns FC<P>

-------------------------------------------------------------------------------- /docs/hierarchy.html: -------------------------------------------------------------------------------- 1 | @auth0/auth0-react
-------------------------------------------------------------------------------- /docs/interfaces/PopupConfigOptions.html: -------------------------------------------------------------------------------- 1 | PopupConfigOptions | @auth0/auth0-react

Interface PopupConfigOptions

interface PopupConfigOptions {
    popup?: any;
    timeoutInSeconds?: number;
}

Properties

Properties

popup?: any

Accepts an already-created popup window to use. If not specified, the SDK 4 | will create its own. This may be useful for platforms like iOS that have 5 | security restrictions around when popups can be invoked (e.g. from a user click event)

6 |
timeoutInSeconds?: number

The number of seconds to wait for a popup response before 7 | throwing a timeout error. Defaults to 60s

8 |
-------------------------------------------------------------------------------- /docs/interfaces/PopupLoginOptions.html: -------------------------------------------------------------------------------- 1 | PopupLoginOptions | @auth0/auth0-react

Interface PopupLoginOptions

interface PopupLoginOptions {
    authorizationParams?: AuthorizationParams;
}

Hierarchy (view full)

Properties

Properties

authorizationParams?: AuthorizationParams

URL parameters that will be sent back to the Authorization Server. This can be known parameters 3 | defined by Auth0 or custom parameters that you define.

4 |
-------------------------------------------------------------------------------- /docs/interfaces/WithAuth0Props.html: -------------------------------------------------------------------------------- 1 | WithAuth0Props | @auth0/auth0-react

Interface WithAuth0Props

Components wrapped in withAuth0 will have an additional auth0 prop

2 |
interface WithAuth0Props {
    auth0: Auth0ContextInterface<User>;
}

Properties

auth0 3 |

Properties

-------------------------------------------------------------------------------- /docs/types/AppState.html: -------------------------------------------------------------------------------- 1 | AppState | @auth0/auth0-react

Type alias AppState

AppState: {
    returnTo?: string;
    [key: string]: any;
}

The state of the application before the user was redirected to the login page.

2 |

Type declaration

  • [key: string]: any
  • Optional returnTo?: string
-------------------------------------------------------------------------------- /docs/types/CacheLocation.html: -------------------------------------------------------------------------------- 1 | CacheLocation | @auth0/auth0-react

Type alias CacheLocation

CacheLocation: "memory" | "localstorage"

The possible locations where tokens can be stored

2 |
-------------------------------------------------------------------------------- /docs/types/Cacheable.html: -------------------------------------------------------------------------------- 1 | Cacheable | @auth0/auth0-react

Type alias Cacheable

Cacheable: WrappedCacheEntry | KeyManifestEntry
-------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # @auth0/auth0-react Examples 2 | 3 | ## Configure an Auth0 application, api and user: 4 | 5 | - Follow the steps to configure an Auth0 Single-Page Application (SPA) in https://auth0.com/docs/quickstart/spa/react/01-login#configure-auth0 6 | - Follow the steps to create an API in https://auth0.com/docs/quickstart/spa/react/02-calling-an-api#create-an-api 7 | - Add a permission to your API of `read:users` following the steps in https://auth0.com/docs/dashboard/guides/apis/add-permissions-apis 8 | 9 | ### Follow the steps to run each of the example applications: 10 | 11 | - [Create React App](./cra-react-router/README.md) 12 | - [Gatsby](./gatsby-app/README.md) 13 | - [NextJS](./nextjs-app/README.md) 14 | - [Users API](./users-api/README.md) 15 | -------------------------------------------------------------------------------- /examples/cra-react-router/.env.sample: -------------------------------------------------------------------------------- 1 | SKIP_PREFLIGHT_CHECK=true 2 | REACT_APP_DOMAIN=your-tenant.auth0.com 3 | REACT_APP_CLIENT_ID=yourclientid 4 | REACT_APP_AUDIENCE=https://api.example.com/users 5 | REACT_APP_API_PORT=3001 6 | -------------------------------------------------------------------------------- /examples/cra-react-router/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | # Intentionally removing package lock because it has problems when using local file resolutions 26 | package-lock.json 27 | -------------------------------------------------------------------------------- /examples/cra-react-router/README.md: -------------------------------------------------------------------------------- 1 | # React Router example 2 | 3 | This is an example of using `@auth0/auth0-react` with `react-router`. 4 | 5 | Follow the steps in [examples/README.md](../README.md) to setup an Auth0 application and API. 6 | 7 | Add the file `./examples/cra-react-router/.env` with the `domain` and `clientId` of the application and `audience` (your API identifier) 8 | 9 | ```dotenv 10 | REACT_APP_DOMAIN=your_domain 11 | REACT_APP_CLIENT_ID=your_client_id 12 | REACT_APP_AUDIENCE=your_audience 13 | SKIP_PREFLIGHT_CHECK=true # To workaround issues with nesting create-react-app in another package 14 | ``` 15 | 16 | Run `npm start` to start the application at http://localhost:3000 17 | 18 | Start the API using the instructions in [examples/users-api/README.md](../users-api/README.md) 19 | -------------------------------------------------------------------------------- /examples/cra-react-router/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cra-react-router", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@auth0/auth0-react": "2.2.4", 7 | "@types/node": "^17.0.29", 8 | "@types/react": "18.3.18", 9 | "@types/react-dom": "18.3.5", 10 | "react": "18.3.1", 11 | "react-dom": "18.3.1", 12 | "react-router-dom": "^6.3.0", 13 | "react-scripts": "^5.0.1", 14 | "typescript": "^4.6.3" 15 | }, 16 | "devDependencies": { 17 | "ajv": "8.16.0" 18 | }, 19 | "scripts": { 20 | "start": "react-scripts start", 21 | "build": "react-scripts build" 22 | }, 23 | "eslintConfig": { 24 | "extends": "react-app" 25 | }, 26 | "browserslist": { 27 | "production": [ 28 | ">0.2%", 29 | "not dead", 30 | "not op_mini all" 31 | ], 32 | "development": [ 33 | "last 1 chrome version", 34 | "last 1 firefox version", 35 | "last 1 safari version" 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /examples/cra-react-router/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auth0/auth0-react/1644bb53f7ef1bc5b62a904a0908587b3f12dd54/examples/cra-react-router/public/favicon.ico -------------------------------------------------------------------------------- /examples/cra-react-router/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 18 | React App 19 | 20 | 21 | 22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/cra-react-router/src/App.css: -------------------------------------------------------------------------------- 1 | .spinner-border { 2 | top: 50%; 3 | position: fixed; 4 | margin-top: -1rem; 5 | } 6 | -------------------------------------------------------------------------------- /examples/cra-react-router/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useAuth0, withAuthenticationRequired } from '@auth0/auth0-react'; 3 | import { Route, Routes } from 'react-router-dom'; 4 | import './App.css'; 5 | import { Nav } from './Nav'; 6 | import { Error } from './Error'; 7 | import { Loading } from './Loading'; 8 | import { Users } from './Users'; 9 | 10 | const ProtectedUsers = withAuthenticationRequired(Users); 11 | 12 | function App() { 13 | const { isLoading, error } = useAuth0(); 14 | 15 | if (isLoading) { 16 | return ; 17 | } 18 | 19 | return ( 20 | <> 21 |