├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── config.yml │ ├── doc_issues.md │ ├── feature_request.md │ └── improvement.md └── workflows │ ├── builder.yml │ ├── codeql-analysis.yml │ ├── notification.yml │ ├── pr-builder.yml │ ├── release-deprecated.yml │ └── release.yml ├── .gitignore ├── CODEOWNERS ├── LICENSE ├── README.md ├── SECURITY.md ├── issue_template.md ├── lerna.json ├── lib ├── .eslintignore ├── .eslintrc.js ├── .jshintrc ├── package.json ├── rollup.config.js ├── src │ ├── client.ts │ ├── constants │ │ ├── client-config.ts │ │ ├── custom-grant-template-tags.ts │ │ ├── data.ts │ │ ├── fetch.ts │ │ ├── index.ts │ │ ├── oidc-endpoints.ts │ │ ├── parameters.ts │ │ └── scopes.ts │ ├── core │ │ ├── authentication-core.ts │ │ └── index.ts │ ├── data │ │ ├── data-layer.ts │ │ └── index.ts │ ├── exception │ │ ├── exception.ts │ │ └── index.ts │ ├── helpers │ │ ├── authentication-helper.ts │ │ ├── crypto-helper.ts │ │ └── index.ts │ ├── index.ts │ ├── models │ │ ├── authorization-url.ts │ │ ├── client-config.ts │ │ ├── crypto.ts │ │ ├── custom-grant.ts │ │ ├── data.ts │ │ ├── fetch.ts │ │ ├── id-token.ts │ │ ├── index.ts │ │ ├── oidc-provider-meta-data.ts │ │ ├── token.ts │ │ └── user.ts │ ├── public-api.ts │ └── utils │ │ ├── authentication-utils.ts │ │ └── index.ts ├── tsconfig.json ├── tsdoc.json └── yarn.lock ├── package.json ├── pull_request_template.md └── yarn.lock /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: ❗️ Issue/Bug report 3 | about: Report issue or bug related to the project 4 | title: '' 5 | labels: 'bug' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the issue:** 11 | 12 | 13 | **How to reproduce:** 14 | 15 | 16 | **Expected behavior:** 17 | 18 | 19 | **Environment information** (_Please complete the following information; remove any unnecessary fields_) **:** 20 | - OS: [e.g., Windows, Linux, Mac] 21 | - Browser: [e.g., Chrome, Firefox] 22 | - SDK Version: [e.g., 0.1.0, 0.1.1] 23 | 24 | --- 25 | 26 | ### Optional Fields 27 | 28 | **Related issues:** 29 | 30 | 31 | **Suggested labels:** 32 | 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: Ask a question 4 | url: https://github.com/wso2/product-is/wiki/Engage-with-the-community 5 | about: Check here on how you can ask a question about the product 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/doc_issues.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 📕 Doc issues 3 | about: Please report documentation issues here 4 | title: '' 5 | labels: 'docs' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your suggestion related to a missing or misleading document? Please describe.** 11 | 12 | 13 | **Describe the improvement** 14 | 15 | 16 | --- 17 | 18 | ### Optional Fields 19 | 20 | **Additional context** 21 | 22 | 23 | **Related Issues:** 24 | 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: ➕ Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: 'feature' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | 12 | 13 | **Describe the solution you would prefer** 14 | 15 | 16 | **Additional context** 17 | 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/improvement.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: ✅ Improvement suggestion 3 | about: Suggest an improvement for the project 4 | title: '' 5 | labels: 'improvement' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your suggestion related to an experience ? Please describe.** 11 | 12 | 13 | **Describe the improvement** 14 | 15 | 16 | **Additional context** 17 | 18 | -------------------------------------------------------------------------------- /.github/workflows/builder.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | # 3 | # WSO2 Inc. licenses this file to you under the Apache License, 4 | # Version 2.0 (the "License"); you may not use this file except 5 | # in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, 11 | # software distributed under the License is distributed on an 12 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | # KIND, either express or implied. See the License for the 14 | # specific language governing permissions and limitations 15 | # under the License. 16 | 17 | # This workflow builds the pushes to the master branch and bumps the version. 18 | 19 | name: Builder 20 | 21 | on: 22 | push: 23 | branches: 24 | - master 25 | paths-ignore: 26 | - '**/package.json' 27 | - '**/yarn.lock' 28 | - 'lerna.json' 29 | 30 | jobs: 31 | build: 32 | 33 | runs-on: ubuntu-latest 34 | 35 | strategy: 36 | matrix: 37 | node-version: [18.x] 38 | 39 | steps: 40 | - uses: actions/checkout@v2 41 | 42 | - name: Use Node.js ${{ matrix.node-version }} 43 | uses: actions/setup-node@v1 44 | with: 45 | node-version: ${{ matrix.node-version }} 46 | 47 | - name: Build 48 | run: | 49 | yarn install --frozen-lockfile 50 | yarn build 51 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | # 3 | # WSO2 Inc. licenses this file to you under the Apache License, 4 | # Version 2.0 (the "License"); you may not use this file except 5 | # in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, 11 | # software distributed under the License is distributed on an 12 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | # KIND, either express or implied. See the License for the 14 | # specific language governing permissions and limitations 15 | # under the License. 16 | 17 | # This configuration runs GitHub's Code Quality Scanning to scan the code for security issues. 18 | name: "CodeQL" 19 | 20 | on: 21 | push: 22 | branches: [master] 23 | pull_request: 24 | # The branches below must be a subset of the branches above 25 | branches: [master] 26 | schedule: 27 | - cron: '0 6 * * 6' 28 | 29 | jobs: 30 | analyze: 31 | name: Analyze 32 | runs-on: ubuntu-latest 33 | 34 | strategy: 35 | fail-fast: false 36 | matrix: 37 | # Override automatic language detection by changing the below list 38 | # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] 39 | language: ['javascript'] 40 | # Learn more... 41 | # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection 42 | 43 | steps: 44 | - name: Checkout repository 45 | uses: actions/checkout@v2 46 | with: 47 | # We must fetch at least the immediate parents so that if this is 48 | # a pull request then we can checkout the head. 49 | fetch-depth: 2 50 | 51 | # If this run was triggered by a pull request event, then checkout 52 | # the head of the pull request instead of the merge commit. 53 | - run: git checkout HEAD^2 54 | if: ${{ github.event_name == 'pull_request' }} 55 | 56 | # Initializes the CodeQL tools for scanning. 57 | - name: Initialize CodeQL 58 | uses: github/codeql-action/init@v1 59 | with: 60 | languages: ${{ matrix.language }} 61 | # If you wish to specify custom queries, you can do so here or in a config file. 62 | # By default, queries listed here will override any specified in a config file. 63 | # Prefix the list here with "+" to use these queries and those in the config file. 64 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 65 | 66 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 67 | # If this step fails, then you should remove it and run the build manually (see below) 68 | - name: Autobuild 69 | uses: github/codeql-action/autobuild@v1 70 | 71 | # ℹ️ Command-line programs to run using the OS shell. 72 | # 📚 https://git.io/JvXDl 73 | 74 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 75 | # and modify them (or add more) to build your code if your project 76 | # uses a compiled language 77 | 78 | #- run: | 79 | # make bootstrap 80 | # make release 81 | 82 | - name: Perform CodeQL Analysis 83 | uses: github/codeql-action/analyze@v1 84 | -------------------------------------------------------------------------------- /.github/workflows/notification.yml: -------------------------------------------------------------------------------- 1 | name: Send Notification 2 | 3 | on: 4 | issues: 5 | types: [opened] 6 | pull_request_target: 7 | types: [opened] 8 | 9 | jobs: 10 | notify: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Escape Issue Title 14 | if: ${{github.event.issue}} 15 | id: escapeIssueTitle 16 | env: 17 | TITLE: ${{ github.event.issue.title }} 18 | run: | 19 | export title=$(echo $TITLE | sed "s/'//g" | sed 's/"//g') 20 | echo "issueTitle=$title" >> $GITHUB_OUTPUT 21 | - name: Escape Issue Body 22 | if: ${{github.event.issue}} 23 | id: escapeIssueBody 24 | env: 25 | BODY: ${{ github.event.issue.body }} 26 | run: | 27 | export body=$(echo $BODY | sed "s/'//g" | sed 's/\"//g') 28 | echo "issueBody=$body" >> $GITHUB_OUTPUT 29 | - name: Escape PR Title 30 | if: ${{github.event.pull_request}} 31 | id: escapePRTitle 32 | env: 33 | TITLE: ${{ github.event.pull_request.title }} 34 | run: | 35 | export title=$(echo $TITLE | sed "s/'//g" | sed 's/"//g') 36 | echo "pRTitle=$title" >> $GITHUB_OUTPUT 37 | - name: Escape PR Body 38 | if: ${{github.event.pull_request}} 39 | id: escapePRBody 40 | env: 41 | BODY: ${{ github.event.pull_request.body }} 42 | run: | 43 | export body=$(echo $BODY | sed "s/'//g" | sed 's/\"//g') 44 | echo "pRBody=$body" >> $GITHUB_OUTPUT 45 | - name: Send notification on issue creation 46 | if: ${{github.event.issue}} 47 | run: | 48 | curl --location --request POST '${{secrets.WEBHOOK_CHAT}}' \ 49 | --header 'Content-Type: application/json' \ 50 | --data-raw '{ 51 | "cardsV2": [ 52 | { 53 | "card": { 54 | "header": { 55 | "title": "PR: ${{ steps.escapeIssueTitle.outputs.issueTitle }}", 56 | "subtitle": "By ${{ github.event.issue.user.login }} in ${{ github.event.repository.name }}", 57 | "imageUrl": "https://avatars.githubusercontent.com/u/583231?v=4", 58 | "imageType": "CIRCLE", 59 | "imageAltText": "GitHub Avatar" 60 | }, 61 | "sections": [ 62 | { 63 | "header": "Issue Details", 64 | "collapsible": false, 65 | "widgets": [ 66 | { 67 | "buttonList": { 68 | "buttons": [ 69 | { 70 | "text": "Open Issue", 71 | "onClick": { 72 | "openLink": { 73 | "url": "${{ github.event.issue.html_url }}" 74 | } 75 | } 76 | } 77 | ] 78 | } 79 | }, 80 | { 81 | "textParagraph": { 82 | "text": "${{ steps.escapeIssueBody.outputs.issueBody }}" 83 | } 84 | } 85 | ] 86 | } 87 | ] 88 | } 89 | } 90 | ] 91 | }' 92 | 93 | - name: Send notification on pull request creation 94 | if: ${{github.event.pull_request}} 95 | run: | 96 | curl --location --request POST '${{secrets.WEBHOOK_CHAT}}' \ 97 | --header 'Content-Type: application/json' \ 98 | --data-raw '{ 99 | "cardsV2": [ 100 | { 101 | "card": { 102 | "header": { 103 | "title": "PR: ${{ steps.escapePRTitle.outputs.prTitle }}", 104 | "subtitle": "By ${{ github.event.pull_request.user.login }} in ${{ github.event.repository.name }}", 105 | "imageUrl": "https://avatars.githubusercontent.com/u/583231?v=4", 106 | "imageType": "CIRCLE", 107 | "imageAltText": "GitHub Avatar" 108 | }, 109 | "sections": [ 110 | { 111 | "header": "PR Details", 112 | "collapsible": false, 113 | "widgets": [ 114 | { 115 | "buttonList": { 116 | "buttons": [ 117 | { 118 | "text": "Open PR", 119 | "onClick": { 120 | "openLink": { 121 | "url": "${{ github.event.pull_request.html_url }}" 122 | } 123 | } 124 | } 125 | ] 126 | } 127 | }, 128 | { 129 | "textParagraph": { 130 | "text": "${{ steps.escapePRBody.outputs.pRBody }}", 131 | } 132 | } 133 | ] 134 | } 135 | ] 136 | } 137 | } 138 | ] 139 | }' 140 | -------------------------------------------------------------------------------- /.github/workflows/pr-builder.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | # 3 | # WSO2 Inc. licenses this file to you under the Apache License, 4 | # Version 2.0 (the "License"); you may not use this file except 5 | # in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, 11 | # software distributed under the License is distributed on an 12 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | # KIND, either express or implied. See the License for the 14 | # specific language governing permissions and limitations 15 | # under the License. 16 | 17 | # This builds the PRs raised to the master branch. 18 | 19 | name: PR Builder 20 | 21 | on: 22 | pull_request: 23 | branches: [ master ] 24 | 25 | jobs: 26 | build: 27 | 28 | runs-on: ubuntu-latest 29 | 30 | strategy: 31 | matrix: 32 | node-version: [18.x] 33 | 34 | steps: 35 | - uses: actions/checkout@v2 36 | 37 | - name: Use Node.js ${{ matrix.node-version }} 38 | uses: actions/setup-node@v1 39 | with: 40 | node-version: ${{ matrix.node-version }} 41 | 42 | - name: Build 43 | run: | 44 | yarn install --frozen-lockfile 45 | yarn build 46 | -------------------------------------------------------------------------------- /.github/workflows/release-deprecated.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Release Deprecated 5 | 6 | on: workflow_dispatch 7 | 8 | jobs: 9 | build: 10 | 11 | runs-on: ubuntu-latest 12 | 13 | strategy: 14 | matrix: 15 | node-version: [14.x] 16 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | with: 21 | ref: deprecated 22 | - name: Use Node.js ${{ matrix.node-version }} 23 | uses: actions/setup-node@v1 24 | with: 25 | node-version: ${{ matrix.node-version }} 26 | - run: npm ci 27 | - run: npm run build --if-present 28 | 29 | - name: publish 30 | env: 31 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} 32 | run: | 33 | echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc 34 | cd packages/oidc-js 35 | npm publish --access public 36 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | # 3 | # WSO2 Inc. licenses this file to you under the Apache License, 4 | # Version 2.0 (the "License"); you may not use this file except 5 | # in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, 11 | # software distributed under the License is distributed on an 12 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | # KIND, either express or implied. See the License for the 14 | # specific language governing permissions and limitations 15 | # under the License. 16 | 17 | # This is a basic workflow to help you get started with Actions 18 | 19 | name: Release 20 | 21 | # Controls when the action will run. 22 | on: 23 | # Allows you to run this workflow manually from the Actions tab 24 | workflow_dispatch: 25 | inputs: 26 | Type: 27 | description: 'Choose which version to bump before release' 28 | required: true 29 | default: 'patch' 30 | 31 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 32 | jobs: 33 | # This workflow contains a single job called "build" 34 | build: 35 | # The type of runner that the job will run on 36 | runs-on: ubuntu-latest 37 | 38 | strategy: 39 | matrix: 40 | node-version: [18.x] 41 | 42 | # Steps represent a sequence of tasks that will be executed as part of the job 43 | steps: 44 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 45 | - uses: actions/checkout@v2 46 | with: 47 | token: ${{secrets.ASGARDIO_GITHUB_BOT_TOKEN}} 48 | if: github.repository == 'asgardeo/asgardeo-auth-js-core' 49 | 50 | - uses: actions/checkout@v2 51 | if: github.repository != 'asgardeo/asgardeo-auth-js-core' 52 | 53 | - name: Use Node.js ${{ matrix.node-version }} 54 | uses: actions/setup-node@v1 55 | with: 56 | node-version: ${{ matrix.node-version }} 57 | 58 | - name: Build 59 | run: | 60 | yarn install --frozen-lockfile 61 | yarn build 62 | 63 | - name: Bump Version 64 | run: | 65 | git config --global user.email "version.bump@github.action.com" 66 | git config --global user.name "asgardeo-github-bot" 67 | yarn run bump-${{ github.event.inputs.Type }}-version 68 | git push --follow-tags 69 | 70 | - name: Pack Release Artifacts 71 | run: | 72 | mkdir artifacts 73 | if test -d samples 74 | then 75 | cd samples 76 | rm -rf **/node_modules/ 77 | for dir in */ ; do 78 | zip -r "../artifacts/${dir%/}.zip" $dir 79 | done 80 | fi 81 | 82 | - name: Release Asgardeo Auth JS SDK 83 | run: | 84 | version=`git describe --tags --abbrev=0` 85 | echo ${{secrets.ASGARDIO_GITHUB_BOT_TOKEN}} | gh auth login --with-token 86 | if test -d samples 87 | then 88 | gh release create $version artifacts/* 89 | else 90 | gh release create $version 91 | fi 92 | 93 | - name: Publish Asgardeo Auth JS SDK 94 | env: 95 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} 96 | run: | 97 | echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc 98 | cp README.md lib 99 | cd lib 100 | npm publish --access public 101 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependency directories 2 | node_modules/ 3 | jspm_packages/ 4 | 5 | # Distribution directories 6 | dist 7 | build/Release 8 | target/ 9 | npm/ 10 | umd/ 11 | 12 | # Cache directories 13 | .npm 14 | .eslintcache 15 | .node_repl_history 16 | 17 | # Log files 18 | logs 19 | *.log 20 | npm-debug.log* 21 | yarn-debug.log* 22 | yarn-error.log* 23 | lerna-debug.log 24 | 25 | # IDEs/Code Editor directries 26 | .vscode 27 | .idea 28 | 29 | # Environment variables files 30 | .env 31 | 32 | # Misc 33 | .classpath 34 | .settings 35 | .factorypath 36 | .DS_Store 37 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @thanujalk @brionmario @NipuniBhagya @inthirakumaaran @thivi @DimalChandrasiri @jeradrutnam 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Please find below the versions that are currently being supported with security updates. 6 | 7 | | Version | Supported | 8 | | ------- | ------------------ | 9 | | 1.0.x | :white_check_mark: | 10 | 11 | ## Reporting Vulnerabilities 12 | 13 | > **Warning** : Please do not create GitHub issues for security vulnerabilities. 14 | 15 | WSO2 takes security issues very seriously. If you have any concerns regarding 16 | our product security or have uncovered a security vulnerability, we strongly 17 | encourage you to report that to our private and highly confidential security 18 | mailing list: security@wso2.com first, without disclosing them in any forums, 19 | sites or other groups - public or private. To protect the end-user security, 20 | these issues could be disclosed in other places only after WSO2 completes its 21 | [Vulnerability Management Process](https://docs.wso2.com/display/Security/WSO2+Security+Vulnerability+Management+Process). 22 | 23 | [WSO2 guidelines for reporting a security vulnerability](https://docs.wso2.com/display/Security/WSO2+Security+Vulnerability+Reporting+Guidelines) page describes how to report a Security Vulnerability and includes a public key if you wish to send secure messages to security@wso2.com 24 | -------------------------------------------------------------------------------- /issue_template.md: -------------------------------------------------------------------------------- 1 | **Description:** 2 | 3 | 4 | **Suggested Labels:** 5 | 6 | 7 | **Suggested Assignees:** 8 | 9 | 10 | **Affected Product Version:** 11 | 12 | **OS, DB, other environment details and versions:** 13 | 14 | **Steps to reproduce:** 15 | 16 | 17 | **Related Issues:** 18 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "command": { 3 | "version": { 4 | "message": "[Asgardeo Release] [GitHub Actions] [Release %s] Bump version" 5 | } 6 | }, 7 | "packages": [ 8 | "lib", 9 | "samples/*" 10 | ], 11 | "npmClient": "yarn", 12 | "version": "5.1.2" 13 | } 14 | -------------------------------------------------------------------------------- /lib/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | umd/ 4 | -------------------------------------------------------------------------------- /lib/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2022, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | const fs = require("fs"); 20 | const path = require("path"); 21 | 22 | // Base ESLint Config which can be extended to be used in the development environment. 23 | 24 | const LICENSE_HEADER_PATTERN_OVERRIDE_FILE_NAME = "license-header-override.js"; 25 | 26 | const LINE_PADDING_RULES = [ 27 | 1, 28 | // Add a new line after const, let, var declarations. 29 | { blankLine: "always", next: "*", prev: [ "const", "let", "var" ] }, 30 | { blankLine: "any", next: [ "const", "let", "var" ], prev: [ "const", "let", "var" ] }, 31 | // Add a new line after directive declarations like `use strict` etc. 32 | { blankLine: "always", next: "*", prev: "directive" }, 33 | { blankLine: "any", next: "directive", prev: "directive" }, 34 | // Add a new line before return statements. 35 | { blankLine: "always", next: "return", prev: "*" }, 36 | // Add a new line try blocks. 37 | { blankLine: "always", next: "try", prev: "*" }, 38 | // Add a new line break statements. 39 | { blankLine: "always", next: "break", prev: "*" }, 40 | // Add a new line continue statements. 41 | { blankLine: "always", next: "continue", prev: "*" }, 42 | // Add a new line before exports. 43 | { blankLine: "always", next: "export", prev: "*" }, 44 | { blankLine: "any", next: "export", prev: "export" }, 45 | // Add a new line before for loops. 46 | { blankLine: "always", next: "for", prev: "*" }, 47 | // Add a new line before classes. 48 | { blankLine: "always", next: "class", prev: "*" }, 49 | // Add a new line after import statements. 50 | { blankLine: "always", next: "*", prev: "import" }, 51 | { blankLine: "any", next: "import", prev: "import" } 52 | ]; 53 | 54 | /** 55 | * Check if an override license header file is defined , if so, 56 | * return that else return the default license header pattern. 57 | * 58 | * @example 59 | * Here's a simple example of overriding the license header pattern.: 60 | * ``` 61 | * // create a `license-header-override.js` at the same level of `.eslintrc.js` 62 | * module.exports = [ 63 | * " * New Company.", 64 | " * Copyright 2022.", 65 | * ]; 66 | * ``` 67 | * 68 | * @returns License Header Pattern. 69 | */ 70 | const getLicenseHeaderPattern = () => { 71 | 72 | const LICENSE_HEADER_DEFAULT_PATTERN = [ 73 | "*", 74 | { 75 | pattern: " Copyright \\(c\\) \\d{4}, WSO2 LLC. \\(https://www.wso2.com\\). All Rights Reserved.", 76 | template: ` * Copyright (c) ${ new Date().getFullYear() 77 | }, WSO2 LLC. (https://www.wso2.com). All Rights Reserved.` 78 | }, 79 | " *", 80 | " * WSO2 LLC. licenses this file to you under the Apache License,", 81 | " * Version 2.0 (the \"License\"); you may not use this file except", 82 | " * in compliance with the License.", 83 | " * You may obtain a copy of the License at", 84 | " *", 85 | " * http://www.apache.org/licenses/LICENSE-2.0", 86 | " *", 87 | " * Unless required by applicable law or agreed to in writing,", 88 | " * software distributed under the License is distributed on an", 89 | " * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY", 90 | " * KIND, either express or implied. See the License for the", 91 | " * specific language governing permissions and limitations", 92 | " * under the License.", 93 | " " 94 | ]; 95 | 96 | if (!fs.existsSync(path.resolve(__dirname, LICENSE_HEADER_PATTERN_OVERRIDE_FILE_NAME))) { 97 | return LICENSE_HEADER_DEFAULT_PATTERN; 98 | } 99 | 100 | return require(path.resolve(__dirname, LICENSE_HEADER_PATTERN_OVERRIDE_FILE_NAME)); 101 | }; 102 | 103 | module.exports = { 104 | env: { 105 | browser: true, 106 | es6: true, 107 | jest: true, 108 | node: true 109 | }, 110 | extends: [ 111 | "eslint:recommended", 112 | "plugin:import/typescript" 113 | ], 114 | globals: { 115 | // no-undef complains about globalThis @see {@link https://github.com/eslint/eslint/issues/11553} 116 | globalThis: false 117 | }, 118 | overrides: [ 119 | { 120 | env: { 121 | browser: true, 122 | es6: true, 123 | node: true 124 | }, 125 | extends: [ 126 | "eslint:recommended", 127 | "plugin:@typescript-eslint/eslint-recommended", 128 | "plugin:@typescript-eslint/recommended" 129 | ], 130 | files: [ "**/*.tsx", "**/*.ts" ], 131 | parser: "@typescript-eslint/parser", 132 | parserOptions: { 133 | ecmaVersion: 9, 134 | sourceType: "module" 135 | }, 136 | rules: { 137 | "@typescript-eslint/ban-types": 1, 138 | "@typescript-eslint/explicit-function-return-type": 0, 139 | "@typescript-eslint/no-empty-function": [ 140 | "error", 141 | { 142 | allow: [ "constructors" ] 143 | } 144 | ], 145 | "@typescript-eslint/no-explicit-any": 0, 146 | "@typescript-eslint/no-inferrable-types": "off", 147 | "@typescript-eslint/no-unused-vars": [ 148 | "warn", 149 | { 150 | argsIgnorePattern: "^_", 151 | caughtErrorsIgnorePattern: "^_", 152 | varsIgnorePattern: "^_" 153 | } 154 | ], 155 | "@typescript-eslint/no-use-before-define": [ 156 | "warn", 157 | { 158 | classes: false, 159 | functions: false, 160 | typedefs: false, 161 | variables: false 162 | } 163 | ], 164 | "@typescript-eslint/padding-line-between-statements": [ ...LINE_PADDING_RULES ], 165 | "@typescript-eslint/typedef": [ 166 | "warn", 167 | { 168 | "arrayDestructuring": false, 169 | "arrowParameter": true, 170 | "memberVariableDeclaration": true, 171 | "objectDestructuring": false, 172 | "parameter": true, 173 | "propertyDeclaration": true, 174 | "variableDeclaration": true, 175 | "variableDeclarationIgnoreFunction": true 176 | } 177 | ], 178 | "eol-last": "error", 179 | // In development, error level is set to `warn`. This will be overridden 180 | // by the production env linting config. 181 | "no-debugger": 1, 182 | // `no-undef` is discouraged in Typescript projects. 183 | // https://github.com/typescript-eslint/typescript-eslint/issues/2477#issuecomment-686892459 184 | "no-undef": 0, 185 | "no-use-before-define": "off", 186 | "padding-line-between-statements": "off" 187 | } 188 | }, 189 | { 190 | "files": "*.json", 191 | "parser": "jsonc-eslint-parser", 192 | "rules": { 193 | "header/header": "off" 194 | } 195 | } 196 | ], 197 | parserOptions: { 198 | ecmaVersion: 9, 199 | sourceType: "module" 200 | }, 201 | plugins: [ 202 | "import", 203 | "eslint-plugin-tsdoc", 204 | "header" 205 | ], 206 | root: true, 207 | rules: { 208 | "array-bracket-spacing": [ 1, "always" ], 209 | "comma-dangle": [ "warn", "never" ], 210 | "eol-last": "error", 211 | "header/header": [ 212 | "warn", 213 | "block", 214 | getLicenseHeaderPattern() 215 | ], 216 | "import/order": [ 217 | "warn", 218 | { 219 | alphabetize: { 220 | caseInsensitive: true, 221 | order: "asc" 222 | }, 223 | groups: [ "builtin", "external", "index", "sibling", "parent", "internal" ] 224 | } 225 | ], 226 | indent: [ 227 | 1, 228 | 4, 229 | { 230 | SwitchCase: 1 231 | } 232 | ], 233 | "lines-between-class-members": [ 234 | 1, 235 | "always", 236 | { 237 | exceptAfterSingleLine: true 238 | } 239 | ], 240 | "max-len": [ 241 | "warn", 242 | { 243 | code: 120 244 | } 245 | ], 246 | "no-alert": 1, 247 | "no-console": "warn", 248 | "no-duplicate-imports": "warn", 249 | "no-restricted-imports": [ 250 | "error", 251 | { 252 | paths: [ 253 | { 254 | message: "Please use import foo from 'lodash-es/foo' instead.", 255 | name: "lodash" 256 | }, 257 | { 258 | message: "Avoid using chain since it is non tree-shakable. Try out flow instead.", 259 | name: "lodash-es/chain" 260 | }, 261 | { 262 | importNames: [ "chain" ], 263 | message: "Avoid using chain since it is non tree-shakable. Try out flow instead.", 264 | name: "lodash-es" 265 | }, 266 | { 267 | message: "Please use import foo from 'lodash-es/foo' instead.", 268 | name: "lodash-es" 269 | } 270 | ], 271 | patterns: [ "@wso2is/**/dist/**", "lodash/**", "lodash/fp/**" ] 272 | } 273 | ], 274 | "no-unreachable": "error", 275 | "object-curly-spacing": [ "warn", "always" ], 276 | "padding-line-between-statements": [ ...LINE_PADDING_RULES ], 277 | quotes: [ "warn", "double" ], 278 | semi: 1, 279 | "sort-imports": [ 280 | "warn", 281 | { 282 | ignoreCase: false, 283 | ignoreDeclarationSort: true, 284 | ignoreMemberSort: false 285 | } 286 | ], 287 | "sort-keys": [ 288 | "warn", 289 | "asc", 290 | { 291 | caseSensitive: true, 292 | minKeys: 2, 293 | natural: false 294 | } 295 | ], 296 | "tsdoc/syntax": "warn" 297 | } 298 | }; 299 | -------------------------------------------------------------------------------- /lib/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "esversion": 6 3 | } 4 | -------------------------------------------------------------------------------- /lib/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@asgardeo/auth-js", 3 | "version": "5.1.2", 4 | "description": "Asgardeo Auth JS SDK to be used in JavaScript and TypeScript applications.", 5 | "keywords": [ 6 | "Asgardeo", 7 | "authentication", 8 | "oidc", 9 | "oauth2", 10 | "spa", 11 | "node.js", 12 | "react-native" 13 | ], 14 | "main": "dist/asgardeo-auth.production.js", 15 | "module": "dist/asgardeo-auth.production.esm.js", 16 | "types": "dist/src/index.d.ts", 17 | "scripts": { 18 | "lint": "eslint --ext .js,.ts .", 19 | "fix-lint": "eslint --ext .js,.ts . --fix", 20 | "build": "cross-env NODE_ENV=production rimraf dist && rimraf umd && npm run type-check && rollup -c", 21 | "build:dev": "cross-env NODE_ENV=development rimraf dist && rimraf umd && npm run type-check && rollup -c", 22 | "type-check": "tsc", 23 | "type-check:watch": "yarn run type-check -- --watch", 24 | "clean": "rimraf dist && rimraf umd && rimraf node_modules", 25 | "prepublish": "yarn run build" 26 | }, 27 | "author": "Asgardeo", 28 | "license": "Apache-2.0", 29 | "devDependencies": { 30 | "@rollup/plugin-commonjs": "^21.0.2", 31 | "@rollup/plugin-eslint": "^8.0.1", 32 | "@rollup/plugin-json": "^4.1.0", 33 | "@rollup/plugin-node-resolve": "^13.1.3", 34 | "@rollup/plugin-replace": "^4.0.0", 35 | "@types/node": "^17.0.21", 36 | "rollup": "^2.69.0", 37 | "rollup-plugin-analyzer": "^4.0.0", 38 | "rollup-plugin-auto-external": "^2.0.0", 39 | "rollup-plugin-terser": "^7.0.2", 40 | "rollup-plugin-typescript2": "^0.31.2", 41 | "rollup-plugin-web-worker-loader": "^1.6.1", 42 | "rollup-pluginutils": "^2.8.2", 43 | "typescript": "~4.5.5" 44 | }, 45 | "repository": { 46 | "type": "git", 47 | "url": "git+https://github.com/asgardeo/asgardeo-auth-js-sdk.git" 48 | }, 49 | "bugs": { 50 | "url": "https://github.com/asgardeo/asgardeo-auth-js-sdk/issues" 51 | }, 52 | "homepage": "https://github.com/asgardeo/asgardeo-auth-js-sdk#readme", 53 | "browserslist": [ 54 | "default" 55 | ] 56 | } 57 | -------------------------------------------------------------------------------- /lib/rollup.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import commonjs from "@rollup/plugin-commonjs"; 20 | import eslint from "@rollup/plugin-eslint"; 21 | import json from "@rollup/plugin-json"; 22 | import resolve from "@rollup/plugin-node-resolve"; 23 | import replace from "@rollup/plugin-replace"; 24 | import analyze from "rollup-plugin-analyzer"; 25 | import autoExternal from "rollup-plugin-auto-external"; 26 | import { terser } from "rollup-plugin-terser"; 27 | import typescript from "rollup-plugin-typescript2"; 28 | import pkg from "./package.json"; 29 | 30 | /** 31 | * UMD bundle type. 32 | */ 33 | const UMD_BUNDLE = "umd"; 34 | 35 | /** 36 | * ESM bundle type. 37 | */ 38 | const ESM_BUNDLE = "esm"; 39 | 40 | /** 41 | * The global variable to be used in UMD and IIFE bundles. 42 | */ 43 | const GLOBAL_VARIABLE = "AsgardeoAuth"; 44 | 45 | /** 46 | * Production environment. 47 | */ 48 | const PRODUCTION = "production"; 49 | 50 | /** 51 | * Development environment. 52 | */ 53 | const DEVELOPMENT = "development"; 54 | 55 | /** 56 | * This returns the name of the bundle file. 57 | * 58 | * @param bundleType - Specifies the type of the bundle. 59 | * 60 | * @returns The name of the output file. 61 | */ 62 | const resolveFileName = (bundleType) => { 63 | switch (bundleType) { 64 | case UMD_BUNDLE: 65 | return pkg.main; 66 | case ESM_BUNDLE: 67 | return pkg.module; 68 | default: 69 | return pkg.main; 70 | } 71 | }; 72 | 73 | /** 74 | * This generates a rollup config object. 75 | * 76 | * @param bundleType - Specifies the type of the bundle. 77 | * @param polyfill - Specifies if the bundle should be polyfilled or not. 78 | * @param env - Specifies if the bundle is for production or development. 79 | * 80 | * @returns Rollup config object. 81 | */ 82 | const generateConfig = (bundleType, env) => { 83 | if (!env) { 84 | env = PRODUCTION; 85 | } 86 | 87 | const fileName = resolveFileName(bundleType); 88 | 89 | const config = { 90 | input: "src/index.ts", 91 | output: { 92 | file: fileName, 93 | format: bundleType, 94 | sourcemap: true 95 | }, 96 | plugins: [ 97 | resolve({ 98 | browser: true, 99 | preferBuiltins: true 100 | }), 101 | commonjs(), 102 | eslint(), 103 | json(), 104 | typescript(), 105 | replace({ 106 | preventAssignment: true, 107 | "process.env.NODE_ENV": 108 | env === PRODUCTION ? JSON.stringify("production") : JSON.stringify("development") 109 | }) 110 | ] 111 | }; 112 | 113 | if (bundleType === UMD_BUNDLE) { 114 | config.output.name = GLOBAL_VARIABLE; 115 | } 116 | 117 | if (env === DEVELOPMENT) { 118 | config.plugins.push(analyze()); 119 | } else { 120 | config.plugins.push(terser()); 121 | // To avoid `Missing shims` and `Missing global variable` warnings. 122 | if (bundleType !== UMD_BUNDLE) { 123 | config.plugins.push( 124 | autoExternal({ 125 | builtins: false, 126 | dependencies: false 127 | }) 128 | ); 129 | } 130 | 131 | config.output.globals = { 132 | axios: "axios" 133 | }; 134 | } 135 | 136 | return config; 137 | }; 138 | 139 | export default [ generateConfig(ESM_BUNDLE, process.env.NODE_ENV), generateConfig(UMD_BUNDLE, process.env.NODE_ENV) ]; 140 | -------------------------------------------------------------------------------- /lib/src/client.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import { 20 | OIDC_SCOPE, 21 | OP_CONFIG_INITIATED, 22 | ResponseMode, 23 | SIGN_OUT_SUCCESS_PARAM, 24 | STATE 25 | } from "./constants"; 26 | import { AuthenticationCore } from "./core"; 27 | import { DataLayer } from "./data"; 28 | import { CryptoHelper } from "./helpers"; 29 | import { 30 | AuthClientConfig, 31 | BasicUserInfo, 32 | CryptoUtils, 33 | CustomGrantConfig, 34 | DecodedIDTokenPayload, 35 | FetchResponse, 36 | GetAuthURLConfig, 37 | OIDCEndpoints, 38 | Store, 39 | TokenResponse 40 | } from "./models"; 41 | 42 | /** 43 | * Default configurations. 44 | */ 45 | const DefaultConfig: Partial> = { 46 | clockTolerance: 300, 47 | enablePKCE: true, 48 | responseMode: ResponseMode.query, 49 | scope: [ OIDC_SCOPE ], 50 | sendCookiesInRequests: true, 51 | validateIDToken: true, 52 | validateIDTokenIssuer: true 53 | }; 54 | 55 | /** 56 | * This class provides the necessary methods needed to implement authentication. 57 | */ 58 | export class AsgardeoAuthClient { 59 | private _dataLayer!: DataLayer; 60 | private _authenticationCore!: AuthenticationCore; 61 | 62 | private static _instanceID: number; 63 | static _authenticationCore: any; 64 | 65 | /** 66 | * This is the constructor method that returns an instance of the . 67 | * 68 | * @param store - The store object. 69 | * 70 | * @example 71 | * ``` 72 | * const _store: Store = new DataStore(); 73 | * const auth = new AsgardeoAuthClient(_store); 74 | * ``` 75 | * 76 | * {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#constructor} 77 | * 78 | * @preserve 79 | */ 80 | public constructor() {} 81 | 82 | /** 83 | * 84 | * This method initializes the SDK with the config data. 85 | * 86 | * @param config - The config object to initialize with. 87 | * 88 | * @example 89 | * const config = \{ 90 | * signInRedirectURL: "http://localhost:3000/sign-in", 91 | * clientID: "client ID", 92 | * baseUrl: "https://localhost:9443" 93 | * \} 94 | * 95 | * await auth.initialize(config); 96 | * 97 | * {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#initialize} 98 | * 99 | * @preserve 100 | */ 101 | public async initialize( 102 | config: AuthClientConfig, 103 | store: Store, 104 | cryptoUtils: CryptoUtils, 105 | instanceID?: number 106 | ): Promise { 107 | const clientId: string = config.clientID; 108 | 109 | if (!AsgardeoAuthClient._instanceID) { 110 | AsgardeoAuthClient._instanceID = 0; 111 | } else { 112 | AsgardeoAuthClient._instanceID += 1; 113 | } 114 | 115 | if (instanceID) { 116 | AsgardeoAuthClient._instanceID = instanceID; 117 | } 118 | 119 | if (!clientId) { 120 | this._dataLayer = new DataLayer(`instance_${ AsgardeoAuthClient._instanceID }`, store); 121 | } else { 122 | this._dataLayer = new DataLayer(`instance_${ AsgardeoAuthClient._instanceID }-${ clientId }`, store); 123 | } 124 | 125 | this._authenticationCore = new AuthenticationCore(this._dataLayer, cryptoUtils); 126 | AsgardeoAuthClient._authenticationCore = new AuthenticationCore(this._dataLayer, cryptoUtils); 127 | 128 | await this._dataLayer.setConfigData({ 129 | ...DefaultConfig, 130 | ...config, 131 | scope: [ 132 | ...(DefaultConfig.scope ?? []), 133 | ...(config.scope?.filter((scope: string) => !DefaultConfig?.scope?.includes(scope)) ?? []) 134 | ] 135 | }); 136 | } 137 | 138 | /** 139 | * This method returns the `DataLayer` object that allows you to access authentication data. 140 | * 141 | * @returns - The `DataLayer` object. 142 | * 143 | * @example 144 | * ``` 145 | * const data = auth.getDataLayer(); 146 | * ``` 147 | * 148 | * {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#getDataLayer} 149 | * 150 | * @preserve 151 | */ 152 | public getDataLayer(): DataLayer { 153 | return this._dataLayer; 154 | } 155 | 156 | /** 157 | * This method returns the `instanceID` variable of the given instance. 158 | * 159 | * @returns - The `instanceID` number. 160 | * 161 | * @example 162 | * ``` 163 | * const instanceId = auth.getInstanceID(); 164 | * ``` 165 | * 166 | * @preserve 167 | */ 168 | public getInstanceID(): number { 169 | return AsgardeoAuthClient._instanceID; 170 | } 171 | 172 | /** 173 | * This is an async method that returns a Promise that resolves with the authorization URL parameters. 174 | * 175 | * @param config - (Optional) A config object to force initialization and pass 176 | * custom path parameters such as the `fidp` parameter. 177 | * @param userID - (Optional) A unique ID of the user to be authenticated. This is useful in multi-user 178 | * scenarios where each user should be uniquely identified. 179 | * 180 | * @returns - A promise that resolves with the authorization URL parameters. 181 | * 182 | * @example 183 | * ``` 184 | * auth.getAuthorizationURLParams().then((params)=>{ 185 | * // console.log(params); 186 | * }).catch((error)=>{ 187 | * // console.error(error); 188 | * }); 189 | * ``` 190 | * 191 | * {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#getAuthorizationURLParams} 192 | * 193 | * @preserve 194 | */ 195 | public async getAuthorizationURLParams( 196 | config?: GetAuthURLConfig, 197 | userID?: string 198 | ): Promise> { 199 | const authRequestConfig: GetAuthURLConfig = { ...config }; 200 | 201 | delete authRequestConfig?.forceInit; 202 | 203 | if (await this._dataLayer.getTemporaryDataParameter(OP_CONFIG_INITIATED)) { 204 | return this._authenticationCore.getAuthorizationURLParams( 205 | authRequestConfig, 206 | userID 207 | ); 208 | } 209 | 210 | return this._authenticationCore 211 | .getOIDCProviderMetaData(config?.forceInit as boolean) 212 | .then(() => { 213 | return this._authenticationCore.getAuthorizationURLParams( 214 | authRequestConfig, 215 | userID 216 | ); 217 | }); 218 | } 219 | 220 | /** 221 | * This is an async method that returns a Promise that resolves with the authorization URL. 222 | * 223 | * @param config - (Optional) A config object to force initialization and pass 224 | * custom path parameters such as the fidp parameter. 225 | * @param userID - (Optional) A unique ID of the user to be authenticated. This is useful in multi-user 226 | * scenarios where each user should be uniquely identified. 227 | * 228 | * @returns - A promise that resolves with the authorization URL. 229 | * 230 | * @example 231 | * ``` 232 | * auth.getAuthorizationURL().then((url)=>{ 233 | * // console.log(url); 234 | * }).catch((error)=>{ 235 | * // console.error(error); 236 | * }); 237 | * ``` 238 | * 239 | * {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#getAuthorizationURL} 240 | * 241 | * @preserve 242 | */ 243 | public async getAuthorizationURL(config?: GetAuthURLConfig, userID?: string): Promise { 244 | const authRequestConfig: GetAuthURLConfig = { ...config }; 245 | 246 | delete authRequestConfig?.forceInit; 247 | 248 | if (await this._dataLayer.getTemporaryDataParameter(OP_CONFIG_INITIATED)) { 249 | return this._authenticationCore.getAuthorizationURL(authRequestConfig, userID); 250 | } 251 | 252 | return this._authenticationCore.getOIDCProviderMetaData(config?.forceInit as boolean).then(() => { 253 | return this._authenticationCore.getAuthorizationURL(authRequestConfig, userID); 254 | }); 255 | } 256 | 257 | /** 258 | * This is an async method that sends a request to obtain the access token and returns a Promise 259 | * that resolves with the token and other relevant data. 260 | * 261 | * @param authorizationCode - The authorization code. 262 | * @param sessionState - The session state. 263 | * @param userID - (Optional) A unique ID of the user to be authenticated. This is useful in multi-user 264 | * scenarios where each user should be uniquely identified. 265 | * 266 | * @returns - A Promise that resolves with the token response. 267 | * 268 | * @example 269 | * ``` 270 | * auth.requestAccessToken(authCode, sessionState).then((token)=>{ 271 | * // console.log(token); 272 | * }).catch((error)=>{ 273 | * // console.error(error); 274 | * }); 275 | * ``` 276 | * 277 | * {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#requestAccessToken} 278 | * 279 | * 280 | * @preserve 281 | */ 282 | public async requestAccessToken( 283 | authorizationCode: string, 284 | sessionState: string, 285 | state: string, 286 | userID?: string, 287 | tokenRequestConfig?: { 288 | params: Record 289 | } 290 | ): Promise { 291 | if (await this._dataLayer.getTemporaryDataParameter(OP_CONFIG_INITIATED)) { 292 | return this._authenticationCore.requestAccessToken(authorizationCode, sessionState, 293 | state, userID, tokenRequestConfig); 294 | } 295 | 296 | return this._authenticationCore.getOIDCProviderMetaData(false).then(() => { 297 | return this._authenticationCore.requestAccessToken(authorizationCode, sessionState, 298 | state, userID, tokenRequestConfig); 299 | }); 300 | } 301 | 302 | /** 303 | * This method returns the sign-out URL. 304 | * 305 | * @param userID - (Optional) A unique ID of the user to be authenticated. This is useful in multi-user 306 | * scenarios where each user should be uniquely identified. 307 | * 308 | * **This doesn't clear the authentication data.** 309 | * 310 | * @returns - A Promise that resolves with the sign-out URL. 311 | * 312 | * @example 313 | * ``` 314 | * const signOutUrl = await auth.getSignOutURL(); 315 | * ``` 316 | * 317 | * {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#getSignOutURL} 318 | * 319 | * @preserve 320 | */ 321 | public async getSignOutURL(userID?: string): Promise { 322 | return this._authenticationCore.getSignOutURL(userID); 323 | } 324 | 325 | /** 326 | * This method returns OIDC service endpoints that are fetched from the `.well-known` endpoint. 327 | * 328 | * @returns - A Promise that resolves with an object containing the OIDC service endpoints. 329 | * 330 | * @example 331 | * ``` 332 | * const endpoints = await auth.getOIDCServiceEndpoints(); 333 | * ``` 334 | * 335 | * {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#getOIDCServiceEndpoints} 336 | * 337 | * @preserve 338 | */ 339 | public async getOIDCServiceEndpoints(): Promise { 340 | return this._authenticationCore.getOIDCServiceEndpoints(); 341 | } 342 | 343 | /** 344 | * This method decodes the payload of the ID token and returns it. 345 | * 346 | * @param userID - (Optional) A unique ID of the user to be authenticated. This is useful in multi-user 347 | * scenarios where each user should be uniquely identified. 348 | * 349 | * @returns - A Promise that resolves with the decoded ID token payload. 350 | * 351 | * @example 352 | * ``` 353 | * const decodedIdToken = await auth.getDecodedIDToken(); 354 | * ``` 355 | * 356 | * {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#getDecodedIDToken} 357 | * 358 | * @preserve 359 | */ 360 | public async getDecodedIDToken(userID?: string): Promise { 361 | return this._authenticationCore.getDecodedIDToken(userID); 362 | } 363 | 364 | /** 365 | * This method returns the ID token. 366 | * 367 | * @param userID - (Optional) A unique ID of the user to be authenticated. This is useful in multi-user 368 | * scenarios where each user should be uniquely identified. 369 | * 370 | * @returns - A Promise that resolves with the ID token. 371 | * 372 | * @example 373 | * ``` 374 | * const idToken = await auth.getIDToken(); 375 | * ``` 376 | * 377 | * {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#getIDToken} 378 | * 379 | * @preserve 380 | */ 381 | public async getIDToken(userID?: string): Promise { 382 | return this._authenticationCore.getIDToken(userID); 383 | } 384 | 385 | /** 386 | * This method returns the basic user information obtained from the ID token. 387 | * 388 | * @param userID - (Optional) A unique ID of the user to be authenticated. This is useful in multi-user 389 | * scenarios where each user should be uniquely identified. 390 | * 391 | * @returns - A Promise that resolves with an object containing the basic user information. 392 | * 393 | * @example 394 | * ``` 395 | * const userInfo = await auth.getBasicUserInfo(); 396 | * ``` 397 | * 398 | * {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#getBasicUserInfo} 399 | * 400 | * @preserve 401 | */ 402 | public async getBasicUserInfo(userID?: string): Promise { 403 | return this._authenticationCore.getBasicUserInfo(userID); 404 | } 405 | 406 | /** 407 | * This method returns the crypto helper object. 408 | * 409 | * @returns - A Promise that resolves with a CryptoHelper object. 410 | * 411 | * @example 412 | * ``` 413 | * const cryptoHelper = await auth.CryptoHelper(); 414 | * ``` 415 | * 416 | * {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#getCryptoHelper} 417 | * 418 | * @preserve 419 | */ 420 | public async getCryptoHelper(): Promise { 421 | return this._authenticationCore.getCryptoHelper(); 422 | } 423 | 424 | /** 425 | * This method revokes the access token. 426 | * 427 | * @param userID - (Optional) A unique ID of the user to be authenticated. This is useful in multi-user 428 | * scenarios where each user should be uniquely identified. 429 | * 430 | * **This method also clears the authentication data.** 431 | * 432 | * @returns - A Promise that returns the response of the revoke-access-token request. 433 | * 434 | * @example 435 | * ``` 436 | * auth.revokeAccessToken().then((response)=>{ 437 | * // console.log(response); 438 | * }).catch((error)=>{ 439 | * // console.error(error); 440 | * }); 441 | * ``` 442 | * 443 | * {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#revokeAccessToken} 444 | * 445 | * @preserve 446 | */ 447 | public revokeAccessToken(userID?: string): Promise { 448 | return this._authenticationCore.revokeAccessToken(userID); 449 | } 450 | 451 | /** 452 | * This method refreshes the access token and returns a Promise that resolves with the new access 453 | * token and other relevant data. 454 | * 455 | * @param userID - (Optional) A unique ID of the user to be authenticated. This is useful in multi-user 456 | * scenarios where each user should be uniquely identified. 457 | * 458 | * @returns - A Promise that resolves with the token response. 459 | * 460 | * @example 461 | * ``` 462 | * auth.refreshAccessToken().then((response)=>{ 463 | * // console.log(response); 464 | * }).catch((error)=>{ 465 | * // console.error(error); 466 | * }); 467 | * ``` 468 | * 469 | * {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#refreshAccessToken} 470 | * 471 | * @preserve 472 | */ 473 | public refreshAccessToken(userID?: string): Promise { 474 | return this._authenticationCore.refreshAccessToken(userID); 475 | } 476 | 477 | /** 478 | * This method returns the access token. 479 | * 480 | * @param userID - (Optional) A unique ID of the user to be authenticated. This is useful in multi-user 481 | * scenarios where each user should be uniquely identified. 482 | * 483 | * @returns - A Promise that resolves with the access token. 484 | * 485 | * @example 486 | * ``` 487 | * const accessToken = await auth.getAccessToken(); 488 | * ``` 489 | * 490 | * {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#getAccessToken} 491 | * 492 | * @preserve 493 | */ 494 | public async getAccessToken(userID?: string): Promise { 495 | return this._authenticationCore.getAccessToken(userID); 496 | } 497 | 498 | /** 499 | * This method sends a custom-grant request and returns a Promise that resolves with the response 500 | * depending on the config passed. 501 | * 502 | * @param config - A config object containing the custom grant configurations. 503 | * @param userID - (Optional) A unique ID of the user to be authenticated. This is useful in multi-user 504 | * scenarios where each user should be uniquely identified. 505 | * 506 | * @returns - A Promise that resolves with the response depending 507 | * on your configurations. 508 | * 509 | * @example 510 | * ``` 511 | * const config = { 512 | * attachToken: false, 513 | * data: { 514 | * client_id: "{{clientID}}", 515 | * grant_type: "account_switch", 516 | * scope: "{{scope}}", 517 | * token: "{{token}}", 518 | * }, 519 | * id: "account-switch", 520 | * returnResponse: true, 521 | * returnsSession: true, 522 | * signInRequired: true 523 | * } 524 | * 525 | * auth.requestCustomGrant(config).then((response)=>{ 526 | * // console.log(response); 527 | * }).catch((error)=>{ 528 | * // console.error(error); 529 | * }); 530 | * ``` 531 | * 532 | * {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#requestCustomGrant} 533 | * 534 | * @preserve 535 | */ 536 | public requestCustomGrant(config: CustomGrantConfig, userID?: string): Promise { 537 | return this._authenticationCore.requestCustomGrant(config, userID); 538 | } 539 | 540 | /** 541 | * This method returns if the user is authenticated or not. 542 | * 543 | * @param userID - (Optional) A unique ID of the user to be authenticated. This is useful in multi-user 544 | * scenarios where each user should be uniquely identified. 545 | * 546 | * @returns - A Promise that resolves with `true` if the user is authenticated, `false` otherwise. 547 | * 548 | * @example 549 | * ``` 550 | * await auth.isAuthenticated(); 551 | * ``` 552 | * 553 | * {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#isAuthenticated} 554 | * 555 | * @preserve 556 | */ 557 | public async isAuthenticated(userID?: string): Promise { 558 | return this._authenticationCore.isAuthenticated(userID); 559 | } 560 | 561 | /** 562 | * This method returns the PKCE code generated during the generation of the authentication URL. 563 | * 564 | * @param userID - (Optional) A unique ID of the user to be authenticated. This is useful in multi-user 565 | * scenarios where each user should be uniquely identified. 566 | * @param state - The state parameter that was passed in the authentication URL. 567 | * 568 | * @returns - A Promise that resolves with the PKCE code. 569 | * 570 | * @example 571 | * ``` 572 | * const pkce = await getPKCECode(); 573 | * ``` 574 | * 575 | * {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#getPKCECode} 576 | * 577 | * @preserve 578 | */ 579 | public async getPKCECode(state: string, userID?: string): Promise { 580 | return this._authenticationCore.getPKCECode(state, userID); 581 | } 582 | 583 | /** 584 | * This method sets the PKCE code to the data store. 585 | * 586 | * @param pkce - The PKCE code. 587 | * @param state - The state parameter that was passed in the authentication URL. 588 | * @param userID - (Optional) A unique ID of the user to be authenticated. This is useful in multi-user 589 | * scenarios where each user should be uniquely identified. 590 | * 591 | * @example 592 | * ``` 593 | * await auth.setPKCECode("pkce_code") 594 | * ``` 595 | * 596 | * {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#setPKCECode} 597 | * 598 | * @preserve 599 | */ 600 | public async setPKCECode(pkce: string, state: string, userID?: string): Promise { 601 | await this._authenticationCore.setPKCECode(pkce, state, userID); 602 | } 603 | 604 | /** 605 | * This method returns if the sign-out is successful or not. 606 | * 607 | * @param signOutRedirectUrl - The URL to which the user has been redirected to after signing-out. 608 | * 609 | * **The server appends path parameters to the `signOutRedirectURL` and these path parameters 610 | * are required for this method to function.** 611 | * 612 | * @returns - `true` if successful, `false` otherwise. 613 | * 614 | * {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#isSignOutSuccessful} 615 | * 616 | * @preserve 617 | */ 618 | public static isSignOutSuccessful(signOutRedirectURL: string): boolean { 619 | const url: URL = new URL(signOutRedirectURL); 620 | const stateParam: string | null = url.searchParams.get(STATE); 621 | const error: boolean = Boolean(url.searchParams.get("error")); 622 | 623 | return stateParam ? stateParam === SIGN_OUT_SUCCESS_PARAM && !error : false; 624 | } 625 | 626 | /** 627 | * This method returns if the sign-out has failed or not. 628 | * 629 | * @param signOutRedirectUrl - The URL to which the user has been redirected to after signing-out. 630 | * 631 | * **The server appends path parameters to the `signOutRedirectURL` and these path parameters 632 | * are required for this method to function.** 633 | * 634 | * @returns - `true` if successful, `false` otherwise. 635 | * 636 | * {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#didSignOutFail} 637 | * 638 | * @preserve 639 | */ 640 | public static didSignOutFail(signOutRedirectURL: string): boolean { 641 | const url: URL = new URL(signOutRedirectURL); 642 | const stateParam: string | null = url.searchParams.get(STATE); 643 | const error: boolean = Boolean(url.searchParams.get("error")); 644 | 645 | return stateParam ? stateParam === SIGN_OUT_SUCCESS_PARAM && error : false; 646 | } 647 | 648 | /** 649 | * This method updates the configuration that was passed into the constructor when instantiating this class. 650 | * 651 | * @param config - A config object to update the SDK configurations with. 652 | * 653 | * @example 654 | * ``` 655 | * const config = { 656 | * signInRedirectURL: "http://localhost:3000/sign-in", 657 | * clientID: "client ID", 658 | * baseUrl: "https://localhost:9443" 659 | * } 660 | * 661 | * await auth.updateConfig(config); 662 | * ``` 663 | * {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#updateConfig} 664 | * 665 | * @preserve 666 | */ 667 | public async updateConfig(config: Partial>): Promise { 668 | await this._authenticationCore.updateConfig(config); 669 | } 670 | 671 | public static async clearUserSessionData(userID?: string): Promise { 672 | await this._authenticationCore.clearUserSessionData(userID); 673 | } 674 | } 675 | -------------------------------------------------------------------------------- /lib/src/constants/client-config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | export enum ResponseMode { 20 | formPost = "form_post", 21 | query = "query", 22 | direct = "direct" 23 | } 24 | -------------------------------------------------------------------------------- /lib/src/constants/custom-grant-template-tags.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | export const TOKEN_TAG: string = "{{token}}"; 20 | export const USERNAME_TAG: string = "{{username}}"; 21 | export const SCOPE_TAG: string = "{{scope}}"; 22 | export const CLIENT_ID_TAG: string = "{{clientID}}"; 23 | export const CLIENT_SECRET_TAG: string = "{{clientSecret}}"; 24 | -------------------------------------------------------------------------------- /lib/src/constants/data.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | export enum Stores { 20 | ConfigData = "config_data", 21 | OIDCProviderMetaData = "oidc_provider_meta_data", 22 | SessionData = "session_data", 23 | TemporaryData = "temporary_data" 24 | } 25 | 26 | export const REFRESH_TOKEN_TIMER: string = "refresh_token_timer"; 27 | export const PKCE_CODE_VERIFIER: string = "pkce_code_verifier"; 28 | export const PKCE_SEPARATOR: string = "#"; 29 | 30 | export const SUPPORTED_SIGNATURE_ALGORITHMS: string[] = [ 31 | "RS256", "RS512", "RS384", "PS256" 32 | ]; 33 | -------------------------------------------------------------------------------- /lib/src/constants/fetch.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | export enum FetchCredentialTypes { 20 | Include = "include", 21 | SameOrigin = "same-origin", 22 | Omit = "omit" 23 | } 24 | -------------------------------------------------------------------------------- /lib/src/constants/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | export * from "./client-config"; 20 | export * from "./oidc-endpoints"; 21 | export * from "./custom-grant-template-tags"; 22 | export * from "./data"; 23 | export * from "./parameters"; 24 | export * from "./scopes"; 25 | export * from "./fetch"; 26 | -------------------------------------------------------------------------------- /lib/src/constants/oidc-endpoints.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2019, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import { OIDCEndpoints } from "../models"; 20 | 21 | export const SERVICE_RESOURCES: OIDCEndpoints = { 22 | authorizationEndpoint: "/oauth2/authorize", 23 | checkSessionIframe: "/oidc/checksession", 24 | endSessionEndpoint: "/oidc/logout", 25 | issuer: "/oauth2/token", 26 | jwksUri: "/oauth2/jwks", 27 | revocationEndpoint: "/oauth2/revoke", 28 | tokenEndpoint: "/oauth2/token", 29 | userinfoEndpoint: "/oauth2/userinfo" 30 | }; 31 | 32 | export const AUTHORIZATION_ENDPOINT: string = "authorization_endpoint"; 33 | export const TOKEN_ENDPOINT: string = "token_endpoint"; 34 | export const REVOKE_TOKEN_ENDPOINT: string = "revocation_endpoint"; 35 | export const END_SESSION_ENDPOINT: string = "end_session_endpoint"; 36 | export const JWKS_ENDPOINT: string = "jwks_uri"; 37 | export const OP_CONFIG_INITIATED: string = "op_config_initiated"; 38 | export const TENANT: string = "tenant"; 39 | export const SIGN_IN_REDIRECT_URL: string = "sign_in_redirect_url"; 40 | export const SIGN_OUT_REDIRECT_URL: string = "sign_out_redirect_url"; 41 | export const OIDC_SESSION_IFRAME_ENDPOINT: string = "check_session_iframe"; 42 | export const OPEN_ID_CONFIG: string = "open_id_config"; 43 | export const REGISTRATION_ENDPOINT: string = "registration_endpoint"; 44 | export const USERINFO_ENDPOINT: string = "userinfo_endpoint"; 45 | export const INTROSPECTION_ENDPOINT: string = "introspection_endpoint"; 46 | export const ISSUER: string = "issuer"; 47 | -------------------------------------------------------------------------------- /lib/src/constants/parameters.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | export const AUTHORIZATION_CODE: string = "code"; 20 | export const SESSION_STATE: string = "session_state"; 21 | export const SIGN_OUT_URL: string = "sign_out_url"; 22 | export const SIGN_OUT_SUCCESS_PARAM: string = "sign_out_success"; 23 | export const STATE: string = "state"; 24 | -------------------------------------------------------------------------------- /lib/src/constants/scopes.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | export const OIDC_SCOPE: string = "openid"; 20 | -------------------------------------------------------------------------------- /lib/src/core/authentication-core.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | import { 19 | AUTHORIZATION_ENDPOINT, 20 | FetchCredentialTypes, 21 | OIDC_SCOPE, 22 | OP_CONFIG_INITIATED, 23 | SESSION_STATE, 24 | SIGN_OUT_SUCCESS_PARAM, 25 | STATE 26 | } from "../constants"; 27 | import { DataLayer } from "../data"; 28 | import { AsgardeoAuthException } from "../exception"; 29 | import { AuthenticationHelper, CryptoHelper } from "../helpers"; 30 | import { 31 | AuthClientConfig, 32 | AuthenticatedUserInfo, 33 | AuthorizationURLParams, 34 | BasicUserInfo, 35 | CryptoUtils, 36 | CustomGrantConfig, 37 | DecodedIDTokenPayload, 38 | FetchRequestConfig, 39 | FetchResponse, 40 | OIDCEndpoints, 41 | OIDCProviderMetaData, 42 | SessionData, 43 | StrictAuthClientConfig, 44 | TokenResponse 45 | } from "../models"; 46 | import { AuthenticationUtils } from "../utils"; 47 | 48 | export class AuthenticationCore { 49 | private _dataLayer: DataLayer; 50 | private _config: () => Promise; 51 | private _oidcProviderMetaData: () => Promise; 52 | private _authenticationHelper: AuthenticationHelper; 53 | private _cryptoUtils: CryptoUtils; 54 | private _cryptoHelper: CryptoHelper; 55 | 56 | public constructor(dataLayer: DataLayer, cryptoUtils: CryptoUtils) { 57 | this._cryptoUtils = cryptoUtils; 58 | this._cryptoHelper = new CryptoHelper(cryptoUtils); 59 | this._authenticationHelper = new AuthenticationHelper(dataLayer, this._cryptoHelper); 60 | this._dataLayer = dataLayer; 61 | this._config = async () => await this._dataLayer.getConfigData(); 62 | this._oidcProviderMetaData = async () => await this._dataLayer.getOIDCProviderMetaData(); 63 | } 64 | 65 | public async getAuthorizationURLParams( 66 | config?: AuthorizationURLParams, 67 | userID?: string 68 | ): Promise> { 69 | const configData: StrictAuthClientConfig = await this._config(); 70 | 71 | const authorizeRequestParams: Map = new Map< 72 | string, 73 | string 74 | >(); 75 | 76 | authorizeRequestParams.set("response_type", "code"); 77 | authorizeRequestParams.set("client_id", configData.clientID); 78 | 79 | if (configData.clientSecret && configData.clientSecret.trim().length > 0) { 80 | authorizeRequestParams.set("client_secret", configData.clientSecret); 81 | } 82 | 83 | let scope: string = OIDC_SCOPE; 84 | 85 | if (configData.scope && configData.scope.length > 0) { 86 | if (!configData.scope.includes(OIDC_SCOPE)) { 87 | configData.scope.push(OIDC_SCOPE); 88 | } 89 | scope = configData.scope.join(" "); 90 | } 91 | 92 | authorizeRequestParams.set("scope", scope); 93 | authorizeRequestParams.set("redirect_uri", configData.signInRedirectURL); 94 | 95 | if (configData.responseMode) { 96 | authorizeRequestParams.set("response_mode", configData.responseMode); 97 | } 98 | 99 | const pkceKey: string = await this._authenticationHelper.generatePKCEKey( 100 | userID 101 | ); 102 | 103 | if (configData.enablePKCE) { 104 | const codeVerifier: string = this._cryptoHelper?.getCodeVerifier(); 105 | const codeChallenge: string = 106 | this._cryptoHelper?.getCodeChallenge(codeVerifier); 107 | 108 | await this._dataLayer.setTemporaryDataParameter( 109 | pkceKey, 110 | codeVerifier, 111 | userID 112 | ); 113 | authorizeRequestParams.set("code_challenge_method", "S256"); 114 | authorizeRequestParams.set("code_challenge", codeChallenge); 115 | } 116 | 117 | if (configData.prompt) { 118 | authorizeRequestParams.set("prompt", configData.prompt); 119 | } 120 | 121 | const customParams: AuthorizationURLParams | undefined = config; 122 | 123 | if (customParams) { 124 | for (const [ key, value ] of Object.entries(customParams)) { 125 | if (key != "" && value != "" && key !== STATE) { 126 | authorizeRequestParams.set(key, value.toString()); 127 | } 128 | } 129 | } 130 | 131 | authorizeRequestParams.set( 132 | STATE, 133 | AuthenticationUtils.generateStateParamForRequestCorrelation( 134 | pkceKey, 135 | customParams ? customParams[STATE]?.toString() : "" 136 | ) 137 | ); 138 | 139 | return authorizeRequestParams; 140 | } 141 | 142 | public async getAuthorizationURL(config?: AuthorizationURLParams, userID?: string): Promise { 143 | const authorizeEndpoint: string = (await this._dataLayer.getOIDCProviderMetaDataParameter( 144 | AUTHORIZATION_ENDPOINT as keyof OIDCProviderMetaData 145 | )) as string; 146 | 147 | if (!authorizeEndpoint || authorizeEndpoint.trim().length === 0) { 148 | throw new AsgardeoAuthException( 149 | "JS-AUTH_CORE-GAU-NF01", 150 | "No authorization endpoint found.", 151 | "No authorization endpoint was found in the OIDC provider meta data from the well-known endpoint " + 152 | "or the authorization endpoint passed to the SDK is empty." 153 | ); 154 | } 155 | 156 | const authorizeRequest: URL = new URL(authorizeEndpoint); 157 | 158 | const authorizeRequestParams: Map = 159 | await this.getAuthorizationURLParams(config, userID); 160 | 161 | for (const [ key, value ] of authorizeRequestParams.entries()) { 162 | authorizeRequest.searchParams.append(key, value); 163 | } 164 | 165 | return authorizeRequest.toString(); 166 | } 167 | 168 | public async requestAccessToken( 169 | authorizationCode: string, 170 | sessionState: string, 171 | state: string, 172 | userID?: string, 173 | tokenRequestConfig?: { 174 | params: Record 175 | } 176 | ): Promise { 177 | const tokenEndpoint: string | undefined = (await this._oidcProviderMetaData()).token_endpoint; 178 | const configData: StrictAuthClientConfig = await this._config(); 179 | 180 | if (!tokenEndpoint || tokenEndpoint.trim().length === 0) { 181 | throw new AsgardeoAuthException( 182 | "JS-AUTH_CORE-RAT1-NF01", 183 | "Token endpoint not found.", 184 | "No token endpoint was found in the OIDC provider meta data returned by the well-known endpoint " + 185 | "or the token endpoint passed to the SDK is empty." 186 | ); 187 | } 188 | 189 | sessionState && (await this._dataLayer.setSessionDataParameter( 190 | SESSION_STATE as keyof SessionData, sessionState, userID)); 191 | 192 | const body: URLSearchParams = new URLSearchParams(); 193 | 194 | body.set("client_id", configData.clientID); 195 | 196 | if (configData.clientSecret && configData.clientSecret.trim().length > 0) { 197 | body.set("client_secret", configData.clientSecret); 198 | } 199 | 200 | const code: string = authorizationCode; 201 | 202 | body.set("code", code); 203 | 204 | body.set("grant_type", "authorization_code"); 205 | body.set("redirect_uri", configData.signInRedirectURL); 206 | 207 | if (tokenRequestConfig?.params) { 208 | Object.entries(tokenRequestConfig.params).forEach(([ key, value ]: [key: string, value: unknown]) => { 209 | body.append(key, value as string); 210 | }); 211 | } 212 | 213 | if (configData.enablePKCE) { 214 | body.set( 215 | "code_verifier", `${await this._dataLayer.getTemporaryDataParameter( 216 | AuthenticationUtils.extractPKCEKeyFromStateParam(state), 217 | userID 218 | )}` 219 | ); 220 | 221 | await this._dataLayer.removeTemporaryDataParameter( 222 | AuthenticationUtils.extractPKCEKeyFromStateParam(state), 223 | userID 224 | ); 225 | } 226 | 227 | let tokenResponse: Response; 228 | 229 | try { 230 | tokenResponse = await fetch(tokenEndpoint, { 231 | body: body, 232 | credentials: configData.sendCookiesInRequests 233 | ? FetchCredentialTypes.Include 234 | : FetchCredentialTypes.SameOrigin, 235 | headers: new Headers(AuthenticationUtils.getTokenRequestHeaders()), 236 | method: "POST" 237 | }); 238 | } catch (error: any) { 239 | throw new AsgardeoAuthException( 240 | "JS-AUTH_CORE-RAT1-NE02", 241 | "Requesting access token failed", 242 | error ?? "The request to get the access token from the server failed." 243 | ); 244 | } 245 | 246 | if (!tokenResponse.ok) { 247 | throw new AsgardeoAuthException( 248 | "JS-AUTH_CORE-RAT1-HE03", 249 | `Requesting access token failed with ${tokenResponse.statusText}`, 250 | await tokenResponse.json() 251 | ); 252 | } 253 | 254 | return await this._authenticationHelper.handleTokenResponse(tokenResponse, userID); 255 | } 256 | 257 | public async refreshAccessToken(userID?: string): Promise { 258 | const tokenEndpoint: string | undefined = (await this._oidcProviderMetaData()).token_endpoint; 259 | const configData: StrictAuthClientConfig = await this._config(); 260 | const sessionData: SessionData = await this._dataLayer.getSessionData(userID); 261 | 262 | if (!sessionData.refresh_token) { 263 | throw new AsgardeoAuthException( 264 | "JS-AUTH_CORE-RAT2-NF01", 265 | "No refresh token found.", 266 | "There was no refresh token found. Asgardeo doesn't return a " + 267 | "refresh token if the refresh token grant is not enabled." 268 | ); 269 | } 270 | 271 | if (!tokenEndpoint || tokenEndpoint.trim().length === 0) { 272 | throw new AsgardeoAuthException( 273 | "JS-AUTH_CORE-RAT2-NF02", 274 | "No refresh token endpoint found.", 275 | "No refresh token endpoint was in the OIDC provider meta data returned by the well-known " + 276 | "endpoint or the refresh token endpoint passed to the SDK is empty." 277 | ); 278 | } 279 | 280 | const body: string[] = []; 281 | 282 | body.push(`client_id=${ configData.clientID }`); 283 | body.push(`refresh_token=${ sessionData.refresh_token }`); 284 | body.push("grant_type=refresh_token"); 285 | 286 | if (configData.clientSecret && configData.clientSecret.trim().length > 0) { 287 | body.push(`client_secret=${ configData.clientSecret }`); 288 | } 289 | 290 | let tokenResponse: Response; 291 | 292 | try { 293 | tokenResponse = await fetch(tokenEndpoint, { 294 | body: body.join("&"), 295 | credentials: configData.sendCookiesInRequests 296 | ? FetchCredentialTypes.Include 297 | : FetchCredentialTypes.SameOrigin, 298 | headers: new Headers(AuthenticationUtils.getTokenRequestHeaders()), 299 | method: "POST" 300 | }); 301 | } catch (error: any) { 302 | throw new AsgardeoAuthException( 303 | "JS-AUTH_CORE-RAT2-NR03", 304 | "Refresh access token request failed.", 305 | error ?? "The request to refresh the access token failed." 306 | ); 307 | } 308 | 309 | if (!tokenResponse.ok) { 310 | throw new AsgardeoAuthException( 311 | "JS-AUTH_CORE-RAT2-HE04", 312 | `Refreshing access token failed with ${tokenResponse.statusText}`, 313 | await tokenResponse.json() 314 | ); 315 | } 316 | 317 | return this._authenticationHelper.handleTokenResponse(tokenResponse, userID); 318 | } 319 | 320 | public async revokeAccessToken(userID?: string): Promise { 321 | const revokeTokenEndpoint: string | undefined = (await this._oidcProviderMetaData()).revocation_endpoint; 322 | const configData: StrictAuthClientConfig = await this._config(); 323 | 324 | if (!revokeTokenEndpoint || revokeTokenEndpoint.trim().length === 0) { 325 | throw new AsgardeoAuthException( 326 | "JS-AUTH_CORE-RAT3-NF01", 327 | "No revoke access token endpoint found.", 328 | "No revoke access token endpoint was found in the OIDC provider meta data returned by " + 329 | "the well-known endpoint or the revoke access token endpoint passed to the SDK is empty." 330 | ); 331 | } 332 | 333 | const body: string[] = []; 334 | 335 | body.push(`client_id=${ configData.clientID }`); 336 | body.push(`token=${ (await this._dataLayer.getSessionData(userID)).access_token }`); 337 | body.push("token_type_hint=access_token"); 338 | 339 | if (configData.clientSecret && configData.clientSecret.trim().length > 0) { 340 | body.push(`client_secret=${ configData.clientSecret }`); 341 | } 342 | 343 | let response: Response; 344 | 345 | try { 346 | response = await fetch(revokeTokenEndpoint, { 347 | body: body.join("&"), 348 | credentials: configData.sendCookiesInRequests 349 | ? FetchCredentialTypes.Include 350 | : FetchCredentialTypes.SameOrigin, 351 | headers: new Headers(AuthenticationUtils.getTokenRequestHeaders()), 352 | method: "POST" 353 | }); 354 | } catch (error: any) { 355 | throw new AsgardeoAuthException( 356 | "JS-AUTH_CORE-RAT3-NE02", 357 | "The request to revoke access token failed.", 358 | error ?? "The request sent to revoke the access token failed." 359 | ); 360 | } 361 | 362 | if (response.status !== 200 || !response.ok) { 363 | throw new AsgardeoAuthException( 364 | "JS-AUTH_CORE-RAT3-HE03", 365 | `Invalid response status received for revoke access token request (${response.statusText}).`, 366 | await response.json() 367 | ); 368 | } 369 | 370 | this._authenticationHelper.clearUserSessionData(userID); 371 | 372 | return Promise.resolve(response); 373 | } 374 | 375 | public async requestCustomGrant( 376 | customGrantParams: CustomGrantConfig, 377 | userID?: string 378 | ): Promise { 379 | const oidcProviderMetadata: OIDCProviderMetaData = await this._oidcProviderMetaData(); 380 | const configData: StrictAuthClientConfig = await this._config(); 381 | 382 | let tokenEndpoint: string | undefined; 383 | 384 | if (customGrantParams.tokenEndpoint && customGrantParams.tokenEndpoint.trim().length !== 0) { 385 | tokenEndpoint = customGrantParams.tokenEndpoint; 386 | } else { 387 | tokenEndpoint = oidcProviderMetadata.token_endpoint; 388 | } 389 | 390 | if (!tokenEndpoint || tokenEndpoint.trim().length === 0) { 391 | throw new AsgardeoAuthException( 392 | "JS-AUTH_CORE-RCG-NF01", 393 | "Token endpoint not found.", 394 | "No token endpoint was found in the OIDC provider meta data returned by the well-known endpoint " + 395 | "or the token endpoint passed to the SDK is empty." 396 | ); 397 | } 398 | 399 | const data: string[] = await Promise.all( 400 | Object.entries(customGrantParams.data).map(async ([ key, value ]: [ key: string, value: any ]) => { 401 | const newValue: string = await this._authenticationHelper.replaceCustomGrantTemplateTags( 402 | value as string, 403 | userID 404 | ); 405 | 406 | return `${ key }=${ newValue }`; 407 | }) 408 | ); 409 | 410 | let requestHeaders: Record = { 411 | ...AuthenticationUtils.getTokenRequestHeaders() 412 | }; 413 | 414 | if (customGrantParams.attachToken) { 415 | requestHeaders = { 416 | ...requestHeaders, 417 | Authorization: `Bearer ${ (await this._dataLayer.getSessionData(userID)).access_token }` 418 | }; 419 | } 420 | 421 | const requestConfig: FetchRequestConfig = { 422 | body: data.join("&"), 423 | credentials: configData.sendCookiesInRequests 424 | ? FetchCredentialTypes.Include 425 | : FetchCredentialTypes.SameOrigin, 426 | headers: new Headers(requestHeaders), 427 | method: "POST" 428 | }; 429 | 430 | let response: Response; 431 | 432 | try { 433 | response = await fetch(tokenEndpoint, requestConfig); 434 | } catch (error: any) { 435 | throw new AsgardeoAuthException( 436 | "JS-AUTH_CORE-RCG-NE02", 437 | "The custom grant request failed.", 438 | error ?? "The request sent to get the custom grant failed." 439 | ); 440 | } 441 | 442 | if (response.status !== 200 || !response.ok) { 443 | throw new AsgardeoAuthException( 444 | "JS-AUTH_CORE-RCG-HE03", 445 | `Invalid response status received for the custom grant request. (${response.statusText})`, 446 | await response.json() 447 | ); 448 | } 449 | 450 | if (customGrantParams.returnsSession) { 451 | return this._authenticationHelper.handleTokenResponse(response, userID); 452 | } else { 453 | return Promise.resolve(await response.json()); 454 | } 455 | } 456 | 457 | public async getBasicUserInfo(userID?: string): Promise { 458 | const sessionData: SessionData = await this._dataLayer.getSessionData(userID); 459 | const authenticatedUser: AuthenticatedUserInfo = this._authenticationHelper 460 | .getAuthenticatedUserInfo(sessionData?.id_token); 461 | 462 | let basicUserInfo: BasicUserInfo = { 463 | allowedScopes: sessionData.scope, 464 | sessionState: sessionData.session_state 465 | }; 466 | 467 | Object.keys(authenticatedUser).forEach((key: string) => { 468 | if ( 469 | authenticatedUser[ key ] === undefined || 470 | authenticatedUser[ key ] === "" || 471 | authenticatedUser[ key ] === null 472 | ) { 473 | delete authenticatedUser[ key ]; 474 | } 475 | }); 476 | 477 | basicUserInfo = { ...basicUserInfo, ...authenticatedUser }; 478 | 479 | return basicUserInfo; 480 | } 481 | 482 | public async getDecodedIDToken(userID?: string): Promise { 483 | const idToken: string = (await this._dataLayer.getSessionData(userID)).id_token; 484 | const payload: DecodedIDTokenPayload = this._cryptoHelper.decodeIDToken(idToken); 485 | 486 | return payload; 487 | } 488 | 489 | public async getCryptoHelper(): Promise { 490 | return this._cryptoHelper; 491 | } 492 | 493 | public async getIDToken(userID?: string): Promise { 494 | return (await this._dataLayer.getSessionData(userID)).id_token; 495 | } 496 | 497 | public async getOIDCProviderMetaData(forceInit: boolean): Promise { 498 | const configData: StrictAuthClientConfig = await this._config(); 499 | 500 | if (!forceInit && (await this._dataLayer.getTemporaryDataParameter(OP_CONFIG_INITIATED))) { 501 | return Promise.resolve(); 502 | } 503 | 504 | const wellKnownEndpoint: string = (configData as any).wellKnownEndpoint; 505 | 506 | if (wellKnownEndpoint) { 507 | 508 | let response: Response; 509 | 510 | try { 511 | response = await fetch(wellKnownEndpoint); 512 | if (response.status !== 200 || !response.ok) { 513 | throw new Error(); 514 | } 515 | } catch { 516 | throw new AsgardeoAuthException( 517 | "JS-AUTH_CORE-GOPMD-HE01", 518 | "Invalid well-known response", 519 | "The well known endpoint response has been failed with an error." 520 | ); 521 | } 522 | 523 | await this._dataLayer.setOIDCProviderMetaData( 524 | await this._authenticationHelper.resolveEndpoints(await response.json()) 525 | ); 526 | await this._dataLayer.setTemporaryDataParameter(OP_CONFIG_INITIATED, true); 527 | 528 | return Promise.resolve(); 529 | } else if ((configData as any).baseUrl) { 530 | try { 531 | await this._dataLayer.setOIDCProviderMetaData( 532 | await this._authenticationHelper.resolveEndpointsByBaseURL()); 533 | } catch (error: any) { 534 | throw new AsgardeoAuthException( 535 | "JS-AUTH_CORE-GOPMD-IV02", 536 | "Resolving endpoints failed.", 537 | error ?? "Resolving endpoints by base url failed." 538 | ); 539 | } 540 | await this._dataLayer.setTemporaryDataParameter(OP_CONFIG_INITIATED, true); 541 | 542 | return Promise.resolve(); 543 | } else { 544 | await this._dataLayer.setOIDCProviderMetaData( 545 | await this._authenticationHelper.resolveEndpointsExplicitly()); 546 | 547 | await this._dataLayer.setTemporaryDataParameter(OP_CONFIG_INITIATED, true); 548 | 549 | return Promise.resolve(); 550 | } 551 | } 552 | 553 | public async getOIDCServiceEndpoints(): Promise { 554 | const oidcProviderMetaData: OIDCProviderMetaData = await this._oidcProviderMetaData(); 555 | 556 | return { 557 | authorizationEndpoint: oidcProviderMetaData.authorization_endpoint ?? "", 558 | checkSessionIframe: oidcProviderMetaData.check_session_iframe ?? "", 559 | endSessionEndpoint: oidcProviderMetaData.end_session_endpoint ?? "", 560 | introspectionEndpoint: oidcProviderMetaData.introspection_endpoint ?? "", 561 | issuer: oidcProviderMetaData.issuer ?? "", 562 | jwksUri: oidcProviderMetaData.jwks_uri ?? "", 563 | registrationEndpoint: oidcProviderMetaData.registration_endpoint ?? "", 564 | revocationEndpoint: oidcProviderMetaData.revocation_endpoint ?? "", 565 | tokenEndpoint: oidcProviderMetaData.token_endpoint ?? "", 566 | userinfoEndpoint: oidcProviderMetaData.userinfo_endpoint ?? "" 567 | }; 568 | } 569 | 570 | public async getSignOutURL(userID?: string): Promise { 571 | const logoutEndpoint: string | undefined = (await this._oidcProviderMetaData())?.end_session_endpoint; 572 | const configData: StrictAuthClientConfig = await this._config(); 573 | 574 | if (!logoutEndpoint || logoutEndpoint.trim().length === 0) { 575 | throw new AsgardeoAuthException( 576 | "JS-AUTH_CORE-GSOU-NF01", 577 | "Sign-out endpoint not found.", 578 | "No sign-out endpoint was found in the OIDC provider meta data returned by the well-known endpoint " + 579 | "or the sign-out endpoint passed to the SDK is empty." 580 | ); 581 | } 582 | 583 | const callbackURL: string = configData?.signOutRedirectURL ?? configData?.signInRedirectURL; 584 | 585 | if (!callbackURL || callbackURL.trim().length === 0) { 586 | throw new AsgardeoAuthException( 587 | "JS-AUTH_CORE-GSOU-NF03", 588 | "No sign-out redirect URL found.", 589 | "The sign-out redirect URL cannot be found or the URL passed to the SDK is empty. " + 590 | "No sign-in redirect URL has been found either. " 591 | ); 592 | } 593 | const queryParams: URLSearchParams = new URLSearchParams(); 594 | 595 | queryParams.set("post_logout_redirect_uri", callbackURL); 596 | 597 | if (configData.sendIdTokenInLogoutRequest) { 598 | const idToken: string = (await this._dataLayer.getSessionData(userID))?.id_token; 599 | 600 | if (!idToken || idToken.trim().length === 0) { 601 | throw new AsgardeoAuthException( 602 | "JS-AUTH_CORE-GSOU-NF02", 603 | "ID token not found.", 604 | "No ID token could be found. Either the session information is lost or you have not signed in." 605 | ); 606 | } 607 | queryParams.set("id_token_hint", idToken); 608 | } else { 609 | queryParams.set("client_id", configData.clientID); 610 | } 611 | 612 | queryParams.set("state", SIGN_OUT_SUCCESS_PARAM); 613 | 614 | return `${logoutEndpoint}?${queryParams.toString()}`; 615 | } 616 | 617 | public async clearUserSessionData(userID?: string): Promise { 618 | await this._authenticationHelper.clearUserSessionData(userID); 619 | } 620 | 621 | public async getAccessToken(userID?: string): Promise { 622 | return (await this._dataLayer.getSessionData(userID))?.access_token; 623 | } 624 | 625 | /** 626 | * The created timestamp of the token response in milliseconds. 627 | * 628 | * @param userID - User ID 629 | * @returns Created at timestamp of the token response in milliseconds. 630 | */ 631 | public async getCreatedAt(userID?: string): Promise { 632 | return (await this._dataLayer.getSessionData(userID))?.created_at; 633 | } 634 | 635 | /** 636 | * The expires timestamp of the token response in seconds. 637 | * 638 | * @param userID - User ID 639 | * @returns Expires in timestamp of the token response in seconds. 640 | */ 641 | public async getExpiresIn(userID?: string): Promise { 642 | return (await this._dataLayer.getSessionData(userID))?.expires_in; 643 | } 644 | 645 | public async isAuthenticated(userID?: string): Promise { 646 | const isAccessTokenAvailable: boolean = Boolean(await this.getAccessToken(userID)); 647 | 648 | // Check if the access token is expired. 649 | const createdAt: number = await this.getCreatedAt(userID); 650 | 651 | // Get the expires in value. 652 | const expiresInString: string = await this.getExpiresIn(userID); 653 | 654 | // If the expires in value is not available, the token is invalid and the user is not authenticated. 655 | if (!expiresInString) { 656 | return false; 657 | } 658 | 659 | // Convert to milliseconds. 660 | const expiresIn: number = parseInt(expiresInString) * 1000; 661 | const currentTime: number = new Date().getTime(); 662 | const isAccessTokenValid: boolean = (createdAt + expiresIn) > currentTime; 663 | 664 | const isAuthenticated: boolean = isAccessTokenAvailable && isAccessTokenValid; 665 | 666 | return isAuthenticated; 667 | } 668 | 669 | public async getPKCECode(state: string, userID?: string): Promise { 670 | return (await this._dataLayer.getTemporaryDataParameter( 671 | AuthenticationUtils.extractPKCEKeyFromStateParam(state), 672 | userID 673 | )) as string; 674 | } 675 | 676 | public async setPKCECode(pkce: string, state: string, userID?: string): Promise { 677 | return await this._dataLayer.setTemporaryDataParameter( 678 | AuthenticationUtils.extractPKCEKeyFromStateParam(state), 679 | pkce, 680 | userID 681 | ); 682 | } 683 | 684 | public async updateConfig(config: Partial>): Promise { 685 | await this._dataLayer.setConfigData(config); 686 | await this.getOIDCProviderMetaData(true); 687 | } 688 | } 689 | -------------------------------------------------------------------------------- /lib/src/core/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | export * from "./authentication-core"; 20 | -------------------------------------------------------------------------------- /lib/src/data/data-layer.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import { Stores } from "../constants"; 20 | import { AuthClientConfig, OIDCProviderMetaData, SessionData, Store, StoreValue, TemporaryData } from "../models"; 21 | 22 | type PartialData = Partial | OIDCProviderMetaData | SessionData | TemporaryData>; 23 | 24 | export const ASGARDEO_SESSION_ACTIVE: string = "asgardeo-session-active"; 25 | 26 | export class DataLayer { 27 | protected _id: string; 28 | protected _store: Store; 29 | public constructor(instanceID: string, store: Store) { 30 | this._id = instanceID; 31 | this._store = store; 32 | } 33 | 34 | protected async setDataInBulk( 35 | key: string, 36 | data: PartialData 37 | ): Promise { 38 | const existingDataJSON: string = (await this._store.getData(key)) ?? null; 39 | const existingData: PartialData = existingDataJSON && JSON.parse(existingDataJSON); 40 | 41 | const dataToBeSaved: PartialData = { ...existingData, ...data }; 42 | const dataToBeSavedJSON: string = JSON.stringify(dataToBeSaved); 43 | 44 | await this._store.setData(key, dataToBeSavedJSON); 45 | } 46 | 47 | protected async setValue( 48 | key: string, 49 | attribute: keyof AuthClientConfig | keyof OIDCProviderMetaData | keyof SessionData | keyof TemporaryData, 50 | value: StoreValue 51 | ): Promise { 52 | const existingDataJSON: string = (await this._store.getData(key)) ?? null; 53 | const existingData: PartialData = existingDataJSON && JSON.parse(existingDataJSON); 54 | 55 | const dataToBeSaved: PartialData = { ...existingData, [ attribute ]: value }; 56 | const dataToBeSavedJSON: string = JSON.stringify(dataToBeSaved); 57 | 58 | await this._store.setData(key, dataToBeSavedJSON); 59 | } 60 | 61 | protected async removeValue( 62 | key: string, 63 | attribute: (keyof AuthClientConfig | keyof OIDCProviderMetaData | keyof SessionData | keyof TemporaryData) 64 | ): Promise { 65 | const existingDataJSON: string = (await this._store.getData(key)) ?? null; 66 | const existingData: PartialData = existingDataJSON && JSON.parse(existingDataJSON); 67 | 68 | const dataToBeSaved: PartialData = { ...existingData }; 69 | 70 | delete dataToBeSaved[ attribute as string ]; 71 | 72 | const dataToBeSavedJSON: string = JSON.stringify(dataToBeSaved); 73 | 74 | await this._store.setData(key, dataToBeSavedJSON); 75 | } 76 | 77 | protected _resolveKey(store: Stores | string, userID?: string): string { 78 | return userID ? `${ store }-${ this._id }-${ userID }` : `${ store }-${ this._id }`; 79 | } 80 | 81 | protected isLocalStorageAvailable(): boolean { 82 | try { 83 | const testValue: string = "__ASGARDEO_AUTH_CORE_LOCAL_STORAGE_TEST__"; 84 | 85 | localStorage.setItem(testValue, testValue); 86 | localStorage.removeItem(testValue); 87 | 88 | return true; 89 | } catch (error) { 90 | return false; 91 | } 92 | } 93 | 94 | public async setConfigData(config: Partial>): Promise { 95 | await this.setDataInBulk(this._resolveKey(Stores.ConfigData), config); 96 | } 97 | 98 | public async setOIDCProviderMetaData(oidcProviderMetaData: Partial): Promise { 99 | this.setDataInBulk(this._resolveKey(Stores.OIDCProviderMetaData), oidcProviderMetaData); 100 | } 101 | 102 | public async setTemporaryData(temporaryData: Partial, userID?: string): Promise { 103 | this.setDataInBulk(this._resolveKey(Stores.TemporaryData, userID), temporaryData); 104 | } 105 | 106 | public async setSessionData(sessionData: Partial, userID?: string): Promise { 107 | this.setDataInBulk(this._resolveKey(Stores.SessionData, userID), sessionData); 108 | } 109 | 110 | public async setCustomData(key: string, customData: Partial, userID?: string): Promise { 111 | this.setDataInBulk(this._resolveKey(key, userID), customData); 112 | } 113 | 114 | public async getConfigData(): Promise> { 115 | return JSON.parse((await this._store.getData(this._resolveKey(Stores.ConfigData))) ?? null); 116 | } 117 | 118 | public async getOIDCProviderMetaData(): Promise { 119 | return JSON.parse((await this._store.getData(this._resolveKey(Stores.OIDCProviderMetaData))) ?? null); 120 | } 121 | 122 | public async getTemporaryData(userID?: string): Promise { 123 | return JSON.parse((await this._store.getData(this._resolveKey(Stores.TemporaryData, userID))) ?? null); 124 | } 125 | 126 | public async getSessionData(userID?: string): Promise { 127 | return JSON.parse((await this._store.getData(this._resolveKey(Stores.SessionData, userID))) ?? null); 128 | } 129 | 130 | public async getCustomData(key: string, userID?: string): Promise { 131 | return JSON.parse((await this._store.getData(this._resolveKey(key, userID))) ?? null); 132 | } 133 | 134 | public setSessionStatus(status: string): void { 135 | // Using local storage to store the session status as it is required to be available across tabs. 136 | this.isLocalStorageAvailable() && localStorage.setItem(`${ASGARDEO_SESSION_ACTIVE}`, status); 137 | } 138 | 139 | public getSessionStatus(): string { 140 | return this.isLocalStorageAvailable() 141 | ? localStorage.getItem(`${ASGARDEO_SESSION_ACTIVE}`) ?? "" 142 | : ""; 143 | } 144 | 145 | public removeSessionStatus(): void { 146 | this.isLocalStorageAvailable() && localStorage.removeItem(`${ASGARDEO_SESSION_ACTIVE}`); 147 | } 148 | 149 | public async removeConfigData(): Promise { 150 | await this._store.removeData(this._resolveKey(Stores.ConfigData)); 151 | } 152 | 153 | public async removeOIDCProviderMetaData(): Promise { 154 | await this._store.removeData(this._resolveKey(Stores.OIDCProviderMetaData)); 155 | } 156 | 157 | public async removeTemporaryData(userID?: string): Promise { 158 | await this._store.removeData(this._resolveKey(Stores.TemporaryData, userID)); 159 | } 160 | 161 | public async removeSessionData(userID?: string): Promise { 162 | await this._store.removeData(this._resolveKey(Stores.SessionData, userID)); 163 | } 164 | 165 | public async getConfigDataParameter(key: keyof AuthClientConfig): Promise { 166 | const data: string = await this._store.getData(this._resolveKey(Stores.ConfigData)); 167 | 168 | return data && JSON.parse(data)[ key ]; 169 | } 170 | 171 | public async getOIDCProviderMetaDataParameter(key: keyof OIDCProviderMetaData): Promise { 172 | const data: string = await this._store.getData(this._resolveKey(Stores.OIDCProviderMetaData)); 173 | 174 | return data && JSON.parse(data)[ key ]; 175 | } 176 | 177 | public async getTemporaryDataParameter(key: keyof TemporaryData, userID?: string): Promise { 178 | const data: string = await this._store.getData(this._resolveKey(Stores.TemporaryData, userID)); 179 | 180 | return data && JSON.parse(data)[ key ]; 181 | } 182 | 183 | public async getSessionDataParameter(key: keyof SessionData, userID?: string): Promise { 184 | const data: string = await this._store.getData(this._resolveKey(Stores.SessionData, userID)); 185 | 186 | return data && JSON.parse(data)[ key ]; 187 | } 188 | 189 | public async setConfigDataParameter(key: keyof AuthClientConfig, value: StoreValue): Promise { 190 | await this.setValue(this._resolveKey(Stores.ConfigData), key, value); 191 | } 192 | 193 | public async setOIDCProviderMetaDataParameter(key: keyof OIDCProviderMetaData, value: StoreValue): Promise { 194 | await this.setValue(this._resolveKey(Stores.OIDCProviderMetaData), key, value); 195 | } 196 | 197 | public async setTemporaryDataParameter( 198 | key: keyof TemporaryData, 199 | value: StoreValue, 200 | userID?: string 201 | ): Promise { 202 | await this.setValue(this._resolveKey(Stores.TemporaryData, userID), key, value); 203 | } 204 | 205 | public async setSessionDataParameter(key: keyof SessionData, value: StoreValue, userID?: string): Promise { 206 | await this.setValue(this._resolveKey(Stores.SessionData, userID), key, value); 207 | } 208 | 209 | public async removeConfigDataParameter(key: keyof AuthClientConfig): Promise { 210 | await this.removeValue(this._resolveKey(Stores.ConfigData), key); 211 | } 212 | 213 | public async removeOIDCProviderMetaDataParameter(key: keyof OIDCProviderMetaData): Promise { 214 | await this.removeValue(this._resolveKey(Stores.OIDCProviderMetaData), key); 215 | } 216 | 217 | public async removeTemporaryDataParameter(key: keyof TemporaryData, userID?: string): Promise { 218 | await this.removeValue(this._resolveKey(Stores.TemporaryData, userID), key); 219 | } 220 | 221 | public async removeSessionDataParameter(key: keyof SessionData, userID?: string): Promise { 222 | await this.removeValue(this._resolveKey(Stores.SessionData, userID), key); 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /lib/src/data/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | export * from "./data-layer"; 20 | -------------------------------------------------------------------------------- /lib/src/exception/exception.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | export class AsgardeoAuthException { 20 | public name: string; 21 | public code: string | undefined; 22 | public message: string; 23 | 24 | public constructor( 25 | code: string, 26 | name: string, 27 | message: string 28 | ) { 29 | this.message = message; 30 | this.name = name; 31 | this.code = code; 32 | Object.setPrototypeOf(this, new.target.prototype); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/src/exception/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | export * from "./exception"; 20 | -------------------------------------------------------------------------------- /lib/src/helpers/authentication-helper.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import { CryptoHelper } from "./crypto-helper"; 20 | import { 21 | AUTHORIZATION_ENDPOINT, 22 | CLIENT_ID_TAG, 23 | CLIENT_SECRET_TAG, 24 | END_SESSION_ENDPOINT, 25 | FetchCredentialTypes, 26 | ISSUER, 27 | JWKS_ENDPOINT, 28 | OIDC_SCOPE, 29 | OIDC_SESSION_IFRAME_ENDPOINT, 30 | PKCE_CODE_VERIFIER, 31 | PKCE_SEPARATOR, 32 | REVOKE_TOKEN_ENDPOINT, 33 | SCOPE_TAG, 34 | SERVICE_RESOURCES, 35 | TOKEN_ENDPOINT, 36 | TOKEN_TAG, 37 | USERINFO_ENDPOINT, 38 | USERNAME_TAG 39 | } from "../constants"; 40 | import { DataLayer } from "../data"; 41 | import { AsgardeoAuthException } from "../exception"; 42 | import { 43 | AuthClientConfig, 44 | AuthenticatedUserInfo, 45 | DecodedIDTokenPayload, 46 | JWKInterface, 47 | OIDCEndpointsInternal, 48 | OIDCProviderMetaData, 49 | RawTokenResponse, 50 | SessionData, 51 | StrictAuthClientConfig, 52 | TemporaryData, 53 | TokenResponse 54 | } from "../models"; 55 | import { AuthenticationUtils } from "../utils"; 56 | 57 | export class AuthenticationHelper { 58 | private _dataLayer: DataLayer; 59 | private _config: () => Promise; 60 | private _oidcProviderMetaData: () => Promise; 61 | private _cryptoHelper: CryptoHelper; 62 | 63 | public constructor(dataLayer: DataLayer, cryptoHelper: CryptoHelper) { 64 | this._dataLayer = dataLayer; 65 | this._config = async () => await this._dataLayer.getConfigData(); 66 | this._oidcProviderMetaData = async () => await this._dataLayer.getOIDCProviderMetaData(); 67 | this._cryptoHelper = cryptoHelper; 68 | } 69 | 70 | public async resolveEndpoints(response: OIDCProviderMetaData): Promise { 71 | const oidcProviderMetaData: OIDCProviderMetaData = {}; 72 | const configData: StrictAuthClientConfig = await this._config(); 73 | 74 | configData.endpoints && 75 | Object.keys(configData.endpoints).forEach((endpointName: string) => { 76 | const snakeCasedName: string = endpointName 77 | .replace(/[A-Z]/g, (letter: string) => `_${ letter.toLowerCase() }`); 78 | 79 | oidcProviderMetaData[ snakeCasedName ] = configData?.endpoints 80 | ? configData.endpoints[ endpointName ] 81 | : ""; 82 | }); 83 | 84 | return { ...response, ...oidcProviderMetaData }; 85 | } 86 | 87 | public async resolveEndpointsExplicitly(): Promise { 88 | const oidcProviderMetaData: OIDCProviderMetaData = {}; 89 | const configData: StrictAuthClientConfig = await this._config(); 90 | 91 | const requiredEndpoints: string[] = [ 92 | AUTHORIZATION_ENDPOINT, 93 | END_SESSION_ENDPOINT, 94 | JWKS_ENDPOINT, 95 | OIDC_SESSION_IFRAME_ENDPOINT, 96 | REVOKE_TOKEN_ENDPOINT, 97 | TOKEN_ENDPOINT, 98 | ISSUER, 99 | USERINFO_ENDPOINT 100 | ]; 101 | 102 | const isRequiredEndpointsContains: boolean = configData.endpoints 103 | ? requiredEndpoints.every((reqEndpointName: string) => { 104 | return configData.endpoints 105 | ? Object.keys(configData.endpoints).some((endpointName: string) => { 106 | const snakeCasedName: string = endpointName.replace( 107 | /[A-Z]/g, 108 | (letter: string) => `_${ letter.toLowerCase() }` 109 | ); 110 | 111 | return snakeCasedName === reqEndpointName; 112 | }) 113 | : false; 114 | }) 115 | : false; 116 | 117 | if (!isRequiredEndpointsContains) { 118 | throw new AsgardeoAuthException( 119 | "JS-AUTH_HELPER-REE-NF01", 120 | "Required endpoints missing", 121 | "Some or all of the required endpoints are missing in the object passed to the `endpoints` " + 122 | "attribute of the`AuthConfig` object." 123 | ); 124 | } 125 | 126 | configData.endpoints && 127 | Object.keys(configData.endpoints).forEach((endpointName: string) => { 128 | const snakeCasedName: string = endpointName 129 | .replace(/[A-Z]/g, (letter: string) => `_${ letter.toLowerCase() }`); 130 | 131 | oidcProviderMetaData[ snakeCasedName ] = configData?.endpoints 132 | ? configData.endpoints[ endpointName ] 133 | : ""; 134 | }); 135 | 136 | return { ...oidcProviderMetaData }; 137 | } 138 | 139 | public async resolveEndpointsByBaseURL(): Promise { 140 | const oidcProviderMetaData: OIDCEndpointsInternal = {}; 141 | const configData: StrictAuthClientConfig = await this._config(); 142 | 143 | const baseUrl: string = (configData as any).baseUrl; 144 | 145 | if (!baseUrl) { 146 | throw new AsgardeoAuthException( 147 | "JS-AUTH_HELPER_REBO-NF01", 148 | "Base URL not defined.", 149 | "Base URL is not defined in AuthClient config." 150 | ); 151 | } 152 | 153 | configData.endpoints && 154 | Object.keys(configData.endpoints).forEach((endpointName: string) => { 155 | const snakeCasedName: string = endpointName 156 | .replace(/[A-Z]/g, (letter: string) => `_${ letter.toLowerCase() }`); 157 | 158 | oidcProviderMetaData[ snakeCasedName ] = configData?.endpoints 159 | ? configData.endpoints[ endpointName ] 160 | : ""; 161 | }); 162 | 163 | const defaultEndpoints: OIDCProviderMetaData = { 164 | [ AUTHORIZATION_ENDPOINT ]: `${baseUrl}${SERVICE_RESOURCES.authorizationEndpoint}`, 165 | [ END_SESSION_ENDPOINT ]: `${baseUrl}${SERVICE_RESOURCES.endSessionEndpoint}`, 166 | [ ISSUER ]: `${baseUrl}${SERVICE_RESOURCES.issuer}`, 167 | [ JWKS_ENDPOINT ]: `${baseUrl}${SERVICE_RESOURCES.jwksUri}`, 168 | [ OIDC_SESSION_IFRAME_ENDPOINT ]: `${baseUrl}${SERVICE_RESOURCES.checkSessionIframe}`, 169 | [ REVOKE_TOKEN_ENDPOINT ]: `${baseUrl}${SERVICE_RESOURCES.revocationEndpoint}`, 170 | [ TOKEN_ENDPOINT ]: `${baseUrl}${SERVICE_RESOURCES.tokenEndpoint}`, 171 | [ USERINFO_ENDPOINT ]: `${baseUrl}${SERVICE_RESOURCES.userinfoEndpoint}` 172 | }; 173 | 174 | return { ...defaultEndpoints, ...oidcProviderMetaData }; 175 | } 176 | 177 | public async validateIdToken(idToken: string): Promise { 178 | const jwksEndpoint: string | undefined = (await this._dataLayer.getOIDCProviderMetaData()).jwks_uri; 179 | const configData: StrictAuthClientConfig = await this._config(); 180 | 181 | if (!jwksEndpoint || jwksEndpoint.trim().length === 0) { 182 | throw new AsgardeoAuthException( 183 | "JS_AUTH_HELPER-VIT-NF01", 184 | "JWKS endpoint not found.", 185 | "No JWKS endpoint was found in the OIDC provider meta data returned by the well-known endpoint " + 186 | "or the JWKS endpoint passed to the SDK is empty." 187 | ); 188 | } 189 | 190 | let response: Response; 191 | 192 | try { 193 | response = await fetch(jwksEndpoint, { 194 | credentials: configData.sendCookiesInRequests 195 | ? FetchCredentialTypes.Include 196 | : FetchCredentialTypes.SameOrigin 197 | }); 198 | } catch (error: any) { 199 | throw new AsgardeoAuthException( 200 | "JS-AUTH_HELPER-VIT-NE02", 201 | "Request to jwks endpoint failed.", 202 | error ?? "The request sent to get the jwks from the server failed." 203 | ); 204 | } 205 | 206 | if (response.status !== 200 || !response.ok) { 207 | throw new AsgardeoAuthException( 208 | "JS-AUTH_HELPER-VIT-HE03", 209 | `Invalid response status received for jwks request (${ response.statusText }).`, 210 | await response.json() 211 | ); 212 | } 213 | 214 | const issuer: string | undefined = (await this._oidcProviderMetaData()).issuer; 215 | 216 | const { keys }: { keys: JWKInterface[]; } = await response.json(); 217 | 218 | const jwk: any = await this._cryptoHelper.getJWKForTheIdToken(idToken.split(".")[ 0 ], keys); 219 | 220 | return this._cryptoHelper.isValidIdToken( 221 | idToken, 222 | jwk, 223 | (await this._config()).clientID, 224 | issuer ?? "", 225 | this._cryptoHelper.decodeIDToken(idToken).sub, 226 | (await this._config()).clockTolerance, 227 | (await this._config()).validateIDTokenIssuer ?? true 228 | ); 229 | } 230 | 231 | public getAuthenticatedUserInfo(idToken: string): AuthenticatedUserInfo { 232 | const payload: DecodedIDTokenPayload = this._cryptoHelper.decodeIDToken(idToken); 233 | const tenantDomain: string = AuthenticationUtils.getTenantDomainFromIdTokenPayload(payload); 234 | const username: string = payload?.username ?? ""; 235 | const givenName: string = payload.given_name ?? ""; 236 | const familyName: string = payload.family_name ?? ""; 237 | const fullName: string = 238 | givenName && familyName 239 | ? `${ givenName } ${ familyName }` 240 | : givenName 241 | ? givenName 242 | : familyName 243 | ? familyName 244 | : ""; 245 | const displayName: string = payload.preferred_username ?? fullName; 246 | 247 | return { 248 | displayName: displayName, 249 | tenantDomain, 250 | username: username, 251 | ...AuthenticationUtils.filterClaimsFromIDTokenPayload(payload) 252 | }; 253 | } 254 | 255 | public async replaceCustomGrantTemplateTags(text: string, userID?: string): Promise { 256 | let scope: string = OIDC_SCOPE; 257 | const configData: StrictAuthClientConfig = await this._config(); 258 | const sessionData: SessionData = await this._dataLayer.getSessionData(userID); 259 | 260 | if (configData.scope && configData.scope.length > 0) { 261 | if (!configData.scope.includes(OIDC_SCOPE)) { 262 | configData.scope.push(OIDC_SCOPE); 263 | } 264 | scope = configData.scope.join(" "); 265 | } 266 | 267 | return text 268 | .replace(TOKEN_TAG, sessionData.access_token) 269 | .replace(USERNAME_TAG, this.getAuthenticatedUserInfo(sessionData.id_token).username) 270 | .replace(SCOPE_TAG, scope) 271 | .replace(CLIENT_ID_TAG, configData.clientID) 272 | .replace(CLIENT_SECRET_TAG, configData.clientSecret ?? ""); 273 | } 274 | 275 | public async clearUserSessionData(userID?: string): Promise { 276 | await this._dataLayer.removeTemporaryData(userID); 277 | await this._dataLayer.removeSessionData(userID); 278 | } 279 | 280 | public async handleTokenResponse(response: Response, userID?: string): Promise { 281 | if (response.status !== 200 || !response.ok) { 282 | throw new AsgardeoAuthException( 283 | "JS-AUTH_HELPER-HTR-NE01", 284 | `Invalid response status received for token request (${ response.statusText }).`, 285 | await response.json() 286 | ); 287 | } 288 | 289 | //Get the response in JSON 290 | const parsedResponse: RawTokenResponse = await response.json(); 291 | 292 | parsedResponse.created_at = new Date().getTime(); 293 | 294 | const shouldValidateIdToken: boolean | undefined = (await this._config()).validateIDToken; 295 | 296 | if (shouldValidateIdToken) { 297 | return this.validateIdToken(parsedResponse.id_token).then(async () => { 298 | await this._dataLayer.setSessionData(parsedResponse, userID); 299 | 300 | const tokenResponse: TokenResponse = { 301 | accessToken: parsedResponse.access_token, 302 | createdAt: parsedResponse.created_at, 303 | expiresIn: parsedResponse.expires_in, 304 | idToken: parsedResponse.id_token, 305 | refreshToken: parsedResponse.refresh_token, 306 | scope: parsedResponse.scope, 307 | tokenType: parsedResponse.token_type 308 | }; 309 | 310 | return Promise.resolve(tokenResponse); 311 | }); 312 | } else { 313 | const tokenResponse: TokenResponse = { 314 | accessToken: parsedResponse.access_token, 315 | createdAt: parsedResponse.created_at, 316 | expiresIn: parsedResponse.expires_in, 317 | idToken: parsedResponse.id_token, 318 | refreshToken: parsedResponse.refresh_token, 319 | scope: parsedResponse.scope, 320 | tokenType: parsedResponse.token_type 321 | }; 322 | 323 | await this._dataLayer.setSessionData(parsedResponse, userID); 324 | 325 | return Promise.resolve(tokenResponse); 326 | } 327 | } 328 | 329 | /** 330 | * This generates a PKCE key with the right index value. 331 | * 332 | * @param userID - The userID to identify a user in a multi-user scenario. 333 | * 334 | * @returns The PKCE key. 335 | */ 336 | public async generatePKCEKey(userID?: string): Promise { 337 | const tempData: TemporaryData = await this._dataLayer.getTemporaryData(userID); 338 | const keys: string[] = []; 339 | 340 | Object.keys(tempData).forEach((key: string) => { 341 | if (key.startsWith(PKCE_CODE_VERIFIER)) { 342 | keys.push(key); 343 | } 344 | }); 345 | 346 | const lastKey: string | undefined = keys.sort().pop(); 347 | const index: number = parseInt(lastKey?.split(PKCE_SEPARATOR)[ 1 ] ?? "-1"); 348 | 349 | return `${ PKCE_CODE_VERIFIER }${ PKCE_SEPARATOR }${ index + 1 }`; 350 | } 351 | } 352 | -------------------------------------------------------------------------------- /lib/src/helpers/crypto-helper.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2022, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import { SUPPORTED_SIGNATURE_ALGORITHMS } from "../constants"; 20 | import { AsgardeoAuthException } from "../exception"; 21 | import { CryptoUtils, DecodedIDTokenPayload, JWKInterface } from "../models"; 22 | 23 | export class CryptoHelper { 24 | private _cryptoUtils: CryptoUtils; 25 | 26 | public constructor(cryptoUtils: CryptoUtils) { 27 | this._cryptoUtils = cryptoUtils; 28 | } 29 | 30 | /** 31 | * Generate code verifier. 32 | * 33 | * @returns code verifier. 34 | */ 35 | public getCodeVerifier(): string { 36 | return this._cryptoUtils.base64URLEncode(this._cryptoUtils.generateRandomBytes(32)); 37 | } 38 | 39 | /** 40 | * Derive code challenge from the code verifier. 41 | * 42 | * @param verifier - Code verifier. 43 | * 44 | * @returns - code challenge. 45 | */ 46 | public getCodeChallenge(verifier: string): string { 47 | return this._cryptoUtils.base64URLEncode(this._cryptoUtils.hashSha256(verifier)); 48 | } 49 | 50 | /** 51 | * Get JWK used for the id_token 52 | * 53 | * @param jwtHeader - header of the id_token. 54 | * @param keys - jwks response. 55 | * 56 | * @returns public key. 57 | * 58 | * @throws 59 | */ 60 | /* eslint-disable @typescript-eslint/no-explicit-any */ 61 | public getJWKForTheIdToken(jwtHeader: string, keys: JWKInterface[]): JWKInterface { 62 | const headerJSON: Record = JSON.parse(this._cryptoUtils.base64URLDecode(jwtHeader)); 63 | 64 | for (const key of keys) { 65 | if (headerJSON.kid === key.kid) { 66 | return key; 67 | } 68 | } 69 | 70 | throw new AsgardeoAuthException( 71 | "JS-CRYPTO_UTIL-GJFTIT-IV01", 72 | "kid not found.", 73 | "Failed to find the 'kid' specified in the id_token. 'kid' found in the header : " + 74 | headerJSON.kid + 75 | ", Expected values: " + 76 | keys.map((key: JWKInterface) => key.kid).join(", ") 77 | ); 78 | } 79 | 80 | /** 81 | * Verify id token. 82 | * 83 | * @param idToken - id_token received from the IdP. 84 | * @param jwk - public key used for signing. 85 | * @param clientID - app identification. 86 | * @param issuer - id_token issuer. 87 | * @param username - Username. 88 | * @param clockTolerance - Allowed leeway for id_tokens (in seconds). 89 | * 90 | * @returns whether the id_token is valid. 91 | * 92 | * @throws 93 | */ 94 | public isValidIdToken( 95 | idToken: string, 96 | jwk: JWKInterface, 97 | clientID: string, 98 | issuer: string, 99 | username: string, 100 | clockTolerance: number | undefined, 101 | validateJwtIssuer: boolean | undefined 102 | ): Promise { 103 | return this._cryptoUtils 104 | .verifyJwt( 105 | idToken, 106 | jwk, 107 | SUPPORTED_SIGNATURE_ALGORITHMS, 108 | clientID, 109 | issuer, 110 | username, 111 | clockTolerance, 112 | validateJwtIssuer 113 | ) 114 | .then((response: boolean) => { 115 | if (response) { 116 | return Promise.resolve(true); 117 | } 118 | 119 | return Promise.reject( 120 | new AsgardeoAuthException( 121 | "JS-CRYPTO_HELPER-IVIT-IV01", 122 | "Invalid ID token.", 123 | "ID token validation returned false" 124 | ) 125 | ); 126 | }); 127 | } 128 | 129 | /** 130 | * This function decodes the payload of an id token and returns it. 131 | * 132 | * @param idToken - The id token to be decoded. 133 | * 134 | * @returns - The decoded payload of the id token. 135 | * 136 | * @throws 137 | */ 138 | public decodeIDToken(idToken: string): DecodedIDTokenPayload { 139 | try { 140 | const utf8String: string = this._cryptoUtils.base64URLDecode(idToken.split(".")[ 1 ]); 141 | const payload: DecodedIDTokenPayload = JSON.parse(utf8String); 142 | 143 | return payload; 144 | } catch (error: any) { 145 | throw new AsgardeoAuthException("JS-CRYPTO_UTIL-DIT-IV01", "Decoding ID token failed.", error); 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /lib/src/helpers/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | export * from "./authentication-helper"; 20 | export * from "./crypto-helper"; 21 | -------------------------------------------------------------------------------- /lib/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | export * from "./public-api"; 20 | -------------------------------------------------------------------------------- /lib/src/models/authorization-url.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | export type AuthorizationURLParams = Omit; 20 | 21 | export interface StrictGetAuthURLConfig { 22 | fidp?: string; 23 | forceInit?: boolean; 24 | } 25 | 26 | export type GetAuthURLConfig = StrictGetAuthURLConfig & Record; 27 | -------------------------------------------------------------------------------- /lib/src/models/client-config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import { OIDCEndpoints } from "./oidc-provider-meta-data"; 20 | import { ResponseMode } from "../constants"; 21 | 22 | export interface DefaultAuthClientConfig { 23 | signInRedirectURL: string; 24 | signOutRedirectURL?: string; 25 | clientHost?: string; 26 | clientID: string; 27 | clientSecret?: string; 28 | enablePKCE?: boolean; 29 | prompt?: string; 30 | responseMode?: ResponseMode; 31 | scope?: string[]; 32 | validateIDToken?: boolean; 33 | validateIDTokenIssuer?: boolean; 34 | /** 35 | * Allowed leeway for id_tokens (in seconds). 36 | */ 37 | clockTolerance?: number; 38 | /** 39 | * Specifies if cookies should be sent with access-token requests, refresh-token requests, 40 | * custom-grant requests, etc. 41 | * 42 | */ 43 | sendCookiesInRequests?: boolean; 44 | sendIdTokenInLogoutRequest?: boolean; 45 | } 46 | 47 | export interface WellKnownAuthClientConfig extends DefaultAuthClientConfig { 48 | wellKnownEndpoint: string; 49 | endpoints?: Partial; 50 | baseUrl?: string; 51 | } 52 | 53 | export interface BaseURLAuthClientConfig extends DefaultAuthClientConfig { 54 | baseUrl: string; 55 | endpoints?: Partial; 56 | wellKnownEndpoint?: string; 57 | } 58 | 59 | export interface ExplicitAuthClientConfig extends DefaultAuthClientConfig { 60 | endpoints: OIDCEndpoints; 61 | baseUrl?: string; 62 | wellKnownEndpoint?: string; 63 | } 64 | 65 | export type StrictAuthClientConfig = 66 | | WellKnownAuthClientConfig 67 | | BaseURLAuthClientConfig 68 | | ExplicitAuthClientConfig; 69 | 70 | export type AuthClientConfig = StrictAuthClientConfig & T; 71 | -------------------------------------------------------------------------------- /lib/src/models/crypto.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | /** 20 | * JWK Model 21 | */ 22 | export interface JWKInterface { 23 | kty: string; 24 | e: string; 25 | use: string; 26 | kid: string; 27 | alg: string; 28 | n: string; 29 | } 30 | 31 | /** 32 | * The interface that defines the CryptoUtils methods. 33 | * 34 | * T is the type of the data passed as the argument into the `base64URLEncode` method. 35 | */ 36 | export interface CryptoUtils { 37 | /** 38 | * Encode the provided data in base64url format. 39 | * 40 | * @param value - Data to be encoded. 41 | * 42 | * @returns Encoded data. 43 | */ 44 | base64URLEncode(value: T): string; 45 | 46 | /** 47 | * Decode the provided data encoded in base64url format. 48 | * 49 | * @param value - Data to be decoded. 50 | * 51 | * @returns Decoded data. 52 | */ 53 | base64URLDecode(value: string): string; 54 | 55 | /** 56 | * Generate random bytes. 57 | * 58 | * @param length - Length of the random bytes to be generated. 59 | * 60 | * @returns Random bytes. 61 | */ 62 | generateRandomBytes(length: number): T; 63 | 64 | /** 65 | * Hash the provided data using SHA-256. 66 | * 67 | * @param data - Data to be hashed. 68 | * 69 | * @returns Hashed data. 70 | */ 71 | hashSha256(data: string): T; 72 | 73 | /** 74 | * Verify the provided JWT. 75 | * 76 | * @param idToken - ID Token to be verified. 77 | * @param jwk - JWK to be used for verification. 78 | * @param algorithms - Algorithms to be used for verification. 79 | * @param clientID - Client ID to be used for verification. 80 | * @param issuer - Issuer to be used for verification. 81 | * @param subject - Subject to be used for verification. 82 | * @param clockTolerance - Clock tolerance to be used for verification. 83 | * 84 | * @returns True if the ID Token is valid. 85 | * 86 | * @throws if the id_token is invalid. 87 | */ 88 | verifyJwt( 89 | idToken: string, 90 | jwk: JWKInterface, 91 | algorithms: string[], 92 | clientID: string, 93 | issuer: string, 94 | subject: string, 95 | clockTolerance?: number, 96 | validateJwtIssuer?: boolean 97 | ): Promise; 98 | } 99 | -------------------------------------------------------------------------------- /lib/src/models/custom-grant.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | export interface CustomGrantConfig{ 20 | id: string; 21 | data: any; 22 | signInRequired: boolean; 23 | attachToken: boolean; 24 | returnsSession: boolean; 25 | tokenEndpoint?: string; 26 | shouldReplayAfterRefresh?: boolean; 27 | } 28 | -------------------------------------------------------------------------------- /lib/src/models/data.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import { OIDCEndpoints } from "."; 20 | 21 | export type StoreValue = string | string[] | boolean | number | OIDCEndpoints; 22 | export type TemporaryData = { [ key: string ]: StoreValue; }; 23 | 24 | export interface SessionData { 25 | access_token: string; 26 | id_token: string; 27 | expires_in: string; 28 | scope: string; 29 | refresh_token?: string; 30 | token_type: string; 31 | session_state: string; 32 | created_at: number; 33 | } 34 | 35 | export interface Store { 36 | setData(key: string, value: string): Promise; 37 | getData(key: string): Promise; 38 | removeData(key: string): Promise; 39 | } 40 | -------------------------------------------------------------------------------- /lib/src/models/fetch.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | export type Method = 20 | | "get" 21 | | "GET" 22 | | "delete" 23 | | "DELETE" 24 | | "head" 25 | | "HEAD" 26 | | "options" 27 | | "OPTIONS" 28 | | "post" 29 | | "POST" 30 | | "put" 31 | | "PUT" 32 | | "patch" 33 | | "PATCH" 34 | | "purge" 35 | | "PURGE" 36 | | "link" 37 | | "LINK" 38 | | "unlink" 39 | | "UNLINK"; 40 | 41 | export type FetchCredentials = "omit" | "same-origin" | "include"; 42 | 43 | export type FetchRedirect = "follow" | "error" | "manual"; 44 | 45 | export interface FetchRequestConfig extends RequestInit { 46 | method?: Method; 47 | url?: string; 48 | credentials?: FetchCredentials; 49 | body?: any; 50 | bodyUsed?: boolean; 51 | cache?: RequestCache; 52 | destination?: string; 53 | integrity?: string; 54 | mode?: RequestMode; 55 | redirect?: FetchRedirect; 56 | referrer?: string; 57 | referrerPolicy?: ReferrerPolicy; 58 | } 59 | 60 | export interface FetchResponse extends ResponseInit { 61 | body: T; 62 | ok: boolean; 63 | bodyUsed?: boolean; 64 | redirected?: boolean; 65 | type: ResponseType; 66 | url: string; 67 | //TODO: Implement trailer property once the MDN docs are completed 68 | json(); 69 | text(); 70 | formData(); 71 | blob(); 72 | arrayBuffer(); 73 | } 74 | 75 | export interface FetchError extends Error { 76 | config: FetchRequestConfig; 77 | code?: string; 78 | request?: any; 79 | response?: FetchResponse; 80 | isFetchError: boolean; 81 | // eslint-disable-next-line @typescript-eslint/ban-types 82 | toJSON: () => object; 83 | } 84 | -------------------------------------------------------------------------------- /lib/src/models/id-token.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | /** 20 | * Interface for the payload of a Decoded ID Token. 21 | */ 22 | export interface StrictDecodedIDTokenPayload { 23 | /** 24 | * The audience for which this token is intended. 25 | */ 26 | aud: string | string[]; 27 | /** 28 | * The uid corresponding to the user who the ID token belonged to. 29 | */ 30 | sub: string; 31 | /** 32 | * The issuer identifier for the issuer of the response. 33 | */ 34 | iss: string; 35 | /** 36 | * The email of the user to whom the ID token belongs. 37 | */ 38 | email?: string; 39 | /** 40 | * Name by which the user wishes to be referred to. 41 | */ 42 | preferred_username?: string; 43 | /** 44 | * The tenant domain of the user to whom the ID token belongs. 45 | */ 46 | tenant_domain?: string; 47 | } 48 | 49 | export interface DecodedIDTokenPayload extends StrictDecodedIDTokenPayload { 50 | /** 51 | * Other custom claims; 52 | */ 53 | [ any: string ]: any; 54 | } 55 | -------------------------------------------------------------------------------- /lib/src/models/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | export * from "./client-config"; 20 | export * from "./data"; 21 | export * from "./oidc-provider-meta-data"; 22 | export * from "./token"; 23 | export * from "./custom-grant"; 24 | export * from "./id-token"; 25 | export * from "./authorization-url"; 26 | export * from "./user"; 27 | export * from "./crypto"; 28 | export * from "./fetch"; 29 | -------------------------------------------------------------------------------- /lib/src/models/oidc-provider-meta-data.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | /** 20 | * The interface of the OpenID Provider Metadata values used by OIDC. 21 | */ 22 | export interface OIDCProviderMetaData { 23 | /** 24 | * URL using the https scheme with no query or fragment component that the OP asserts as its Issuer Identifier. 25 | */ 26 | issuer?: string; 27 | /** 28 | * URL of the OP's OAuth 2.0 Authorization Endpoint. 29 | */ 30 | authorization_endpoint?: string; 31 | /** 32 | * URL of the OP's OAuth 2.0 Token Endpoint. 33 | */ 34 | token_endpoint?: string; 35 | /** 36 | * URL of the OP's UserInfo Endpoint. 37 | */ 38 | userinfo_endpoint?: string; 39 | /** 40 | * URL of the OP's JSON Web Key Set [JWK] document. 41 | * This contains the signing key(s) the RP uses to validate signatures from the OP. 42 | */ 43 | jwks_uri?: string; 44 | /** 45 | * URL of the OP's Dynamic Client Registration Endpoint 46 | */ 47 | registration_endpoint?: string; 48 | /** 49 | * JSON array containing a list of the OAuth 2.0 [RFC6749] scope values that this server supports. 50 | */ 51 | scopes_supported?: string[]; 52 | /** 53 | * JSON array containing a list of the OAuth 2.0 response_type values that this OP supports. 54 | */ 55 | response_types_supported?: string[]; 56 | /** 57 | * JSON array containing a list of the OAuth 2.0 response_mode values that this OP supports. 58 | */ 59 | response_modes_supported?: string[]; 60 | /** 61 | * JSON array containing a list of the OAuth 2.0 Grant Type values that this OP supports. 62 | */ 63 | grant_types_supported?: string[]; 64 | /** 65 | * JSON array containing a list of the Authentication Context Class References that this OP supports. 66 | */ 67 | acr_values_supported?: string[]; 68 | /** 69 | * JSON array containing a list of the Subject Identifier types that this OP supports. 70 | */ 71 | subject_types_supported?: string[]; 72 | /** 73 | * JSON array containing a list of the JWS signing algorithms (alg values) 74 | * supported by the OP for the ID Token to encode the Claims in a JWT [JWT]. 75 | */ 76 | id_token_signing_alg_values_supported?: string[]; 77 | /** 78 | * JSON array containing a list of the JWE encryption algorithms (alg values) 79 | * supported by the OP for the ID Token to encode the Claims in a JWT [JWT]. 80 | */ 81 | id_token_encryption_alg_values_supported?: string[]; 82 | /** 83 | * JSON array containing a list of the JWE encryption algorithms (enc values) 84 | * supported by the OP for the ID Token to encode the Claims in a JWT [JWT]. 85 | */ 86 | id_token_encryption_enc_values_supported?: string[]; 87 | /** 88 | * JSON array containing a list of the JWS [JWS] signing algorithms (alg values) [JWA] 89 | * supported by the UserInfo Endpoint to encode the Claims in a JWT [JWT]. 90 | */ 91 | userinfo_signing_alg_values_supported?: string[]; 92 | /** 93 | * JSON array containing a list of the JWE [JWE] encryption algorithms (alg values) 94 | * [JWA] supported by the UserInfo Endpoint to encode the Claims in a JWT [JWT]. 95 | */ 96 | userinfo_encryption_alg_values_supported?: string[]; 97 | /** 98 | * JSON array containing a list of the JWE encryption algorithms (enc values) [JWA] 99 | * supported by the UserInfo Endpoint to encode the Claims in a JWT [JWT] 100 | */ 101 | userinfo_encryption_enc_values_supported?: string[]; 102 | /** 103 | * JSON array containing a list of the JWS signing algorithms (alg values) supported by the OP for Request Objects 104 | */ 105 | request_object_signing_alg_values_supported?: string[]; 106 | /** 107 | * JSON array containing a list of the JWE encryption algorithms (alg values) 108 | * supported by the OP for Request Objects. 109 | */ 110 | request_object_encryption_alg_values_supported?: string[]; 111 | /** 112 | * JSON array containing a list of the JWE encryption algorithms (enc values) 113 | * supported by the OP for Request Objects. 114 | */ 115 | request_object_encryption_enc_values_supported?: string[]; 116 | /** 117 | * JSON array containing a list of Client Authentication methods supported by this Token Endpoint. 118 | */ 119 | token_endpoint_auth_methods_supported?: string[]; 120 | /** 121 | * JSON array containing a list of the JWS signing algorithms (alg values) supported by the Token Endpoint 122 | * for the signature on the JWT [JWT] used to authenticate the Client at the Token Endpoint for the 123 | * private_key_jwt and client_secret_jwt authentication methods. 124 | */ 125 | token_endpoint_auth_signing_alg_values_supported?: string[]; 126 | /** 127 | * JSON array containing a list of the display parameter values that the OpenID Provider supports. 128 | */ 129 | display_values_supported?: string[]; 130 | /** 131 | * JSON array containing a list of the Claim Types that the OpenID Provider supports. 132 | */ 133 | claim_types_supported?: string[]; 134 | /** 135 | * JSON array containing a list of the Claim Names of the Claims that 136 | * the OpenID Provider MAY be able to supply values for. 137 | */ 138 | claims_supported?: string[]; 139 | /** 140 | * URL of a page containing human-readable information that developers 141 | * might want or need to know when using the OpenID Provider. 142 | */ 143 | service_documentation?: string; 144 | /** 145 | * Languages and scripts supported for values in Claims being returned, represented as a JSON array 146 | * of BCP47 [RFC5646] language tag values. Not all languages and scripts are necessarily 147 | * supported for all Claim values. 148 | */ 149 | claims_locales_supported?: string[]; 150 | /** 151 | * Languages and scripts supported for the user interface, 152 | * represented as a JSON array of BCP47 [RFC5646] language tag values. 153 | */ 154 | ui_locales_supported?: string[]; 155 | /** 156 | * Boolean value specifying whether the OP supports use of the claims parameter, 157 | * with true indicating support. If omitted, the default value is false. 158 | */ 159 | claims_parameter_supported?: boolean; 160 | /** 161 | * Boolean value specifying whether the OP supports use of the request parameter, 162 | * with true indicating support. If omitted, the default value is false. 163 | */ 164 | request_parameter_supported?: boolean; 165 | /** 166 | * Boolean value specifying whether the OP supports use of the request_uri parameter, 167 | * with true indicating support. If omitted, the default value is true. 168 | */ 169 | request_uri_parameter_supported?: boolean; 170 | /** 171 | * Boolean value specifying whether the OP requires any request_uri values used to be 172 | * pre-registered using the request_uris registration parameter. 173 | */ 174 | require_request_uri_registration?: boolean; 175 | /** 176 | * URL that the OpenID Provider provides to the person registering the Client 177 | * to read about the OP's requirements on how the Relying Party can use the data provided by the OP. 178 | */ 179 | op_policy_uri?: string; 180 | /** 181 | * URL that the OpenID Provider provides to the person registering the Client 182 | * to read about OpenID Provider's terms of service. 183 | */ 184 | op_tos_uri?: string; 185 | /** 186 | * URL of the authorization server's OAuth 2.0 revocation 187 | * endpoint. 188 | */ 189 | revocation_endpoint?: string; 190 | /** 191 | * JSON array containing a list of client authentication 192 | * methods supported by this revocation endpoint. 193 | */ 194 | revocation_endpoint_auth_methods_supported?: string[]; 195 | /** 196 | * JSON array containing a list of the JWS signing 197 | * algorithms ("alg" values) supported by the revocation endpoint for 198 | * the signature on the JWT [JWT] used to authenticate the client at 199 | * the revocation endpoint for the "private_key_jwt" and 200 | * "client_secret_jwt" authentication methods. 201 | */ 202 | revocation_endpoint_auth_signing_alg_values_supported?: string[]; 203 | /** 204 | * URL of the authorization server's OAuth 2.0 205 | * introspection endpoint. 206 | */ 207 | introspection_endpoint?: string; 208 | /** 209 | * JSON array containing a list of client authentication 210 | * methods supported by this introspection endpoint. 211 | */ 212 | introspection_endpoint_auth_methods_supported?: string[]; 213 | /** 214 | * JSON array containing a list of the JWS signing 215 | * algorithms ("alg" values) supported by the introspection endpoint 216 | * for the signature on the JWT [JWT] used to authenticate the client 217 | * at the introspection endpoint for the "private_key_jwt" and 218 | * "client_secret_jwt" authentication methods. 219 | */ 220 | introspection_endpoint_auth_signing_alg_values_supported?: string[]; 221 | /** 222 | * JSON array containing a list of Proof Key for Code 223 | * Exchange (PKCE) [RFC7636] code challenge methods supported by this 224 | * authorization server. 225 | */ 226 | code_challenge_methods_supported?: string[]; 227 | /** 228 | * URL of an OP iframe that supports cross-origin communications for session state information with the RP 229 | * Client, using the HTML5 postMessage API. 230 | */ 231 | check_session_iframe?: string; 232 | /** 233 | * URL at the OP to which an RP can perform a redirect to request that the End-User be logged out at the 234 | * OP. 235 | */ 236 | end_session_endpoint?: string; 237 | /** 238 | * Boolean value specifying whether the OP supports back-channel logout, with true indicating support. 239 | * If omitted, the default value is false. 240 | */ 241 | backchannel_logout_supported?: boolean; 242 | /** 243 | * Boolean value specifying whether the OP can pass a sid (session ID) Claim in the Logout Token to 244 | * identify the RP session with the OP. 245 | */ 246 | backchannel_logout_session_supported?: boolean; 247 | } 248 | 249 | export interface OIDCEndpointsInternal { 250 | authorization_endpoint?: string; 251 | token_endpoint?: string; 252 | userinfo_endpoint?: string; 253 | jwks_uri?: string; 254 | registration_endpoint?: string; 255 | revocation_endpoint?: string; 256 | introspection_endpoint?: string; 257 | check_session_iframe?: string; 258 | end_session_endpoint?: string; 259 | issuer?: string; 260 | } 261 | export interface OIDCEndpoints { 262 | authorizationEndpoint: string; 263 | tokenEndpoint: string; 264 | userinfoEndpoint: string; 265 | jwksUri: string; 266 | registrationEndpoint?: string; 267 | revocationEndpoint: string; 268 | introspectionEndpoint?: string; 269 | checkSessionIframe: string; 270 | endSessionEndpoint: string; 271 | issuer: string; 272 | } 273 | -------------------------------------------------------------------------------- /lib/src/models/token.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | /** 20 | * Interface of the OAuth2/OIDC tokens. 21 | */ 22 | export interface TokenResponse { 23 | accessToken: string; 24 | idToken: string; 25 | expiresIn: string; 26 | scope: string; 27 | refreshToken: string; 28 | tokenType: string; 29 | createdAt: number; 30 | } 31 | 32 | export interface RawTokenResponse { 33 | access_token: string; 34 | id_token: string; 35 | expires_in: string; 36 | scope: string; 37 | refresh_token: string; 38 | token_type: string; 39 | created_at: number; 40 | } 41 | -------------------------------------------------------------------------------- /lib/src/models/user.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | /** 20 | * Interface containing the basic user information. 21 | */ 22 | export interface BasicUserInfo { 23 | /** 24 | * The email address of the user. 25 | */ 26 | email?: string | undefined; 27 | /** 28 | * The username of the user. 29 | */ 30 | username?: string | undefined; 31 | /** 32 | * The display name of the user. It is the preferred_username in the id token payload or the `sub`. 33 | */ 34 | displayName?: string | undefined; 35 | /** 36 | * The scopes allowed for the user. 37 | */ 38 | allowedScopes: string; 39 | /** 40 | * The tenant domain to which the user belongs. 41 | */ 42 | tenantDomain?: string | undefined; 43 | /** 44 | * The session state. 45 | */ 46 | sessionState: string; 47 | /** 48 | * The `uid` corresponding to the user who the ID token belongs to. 49 | */ 50 | sub?: string; 51 | /** 52 | * Any other attributes retrieved from teh `id_token`. 53 | */ 54 | [ key: string ]: any; 55 | } 56 | 57 | /** 58 | * Interface of the authenticated user. 59 | */ 60 | export interface AuthenticatedUserInfo { 61 | /** 62 | * Authenticated user's display name. 63 | */ 64 | displayName?: string | undefined; 65 | /** 66 | * Authenticated user's display name. 67 | * @deprecated Use `displayName` instead. 68 | */ 69 | display_name?: string | undefined; 70 | /** 71 | * User's email. 72 | */ 73 | email?: string | undefined; 74 | /** 75 | * Available scopes. 76 | */ 77 | scope?: string | undefined; 78 | /** 79 | * Authenticated user's tenant domain. 80 | */ 81 | tenantDomain?: string | undefined; 82 | /** 83 | * Authenticated user's username. 84 | */ 85 | username: string; 86 | [key: string]: any; 87 | } 88 | -------------------------------------------------------------------------------- /lib/src/public-api.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | export * from "./client"; 20 | export * from "./models"; 21 | export * from "./constants/client-config"; 22 | export * from "./constants/custom-grant-template-tags"; 23 | export * from "./constants/parameters"; 24 | export * from "./constants/data"; 25 | export * from "./constants/parameters"; 26 | export * from "./constants/scopes"; 27 | export * from "./helpers/crypto-helper"; 28 | export * from "./utils"; 29 | export * from "./exception"; 30 | export * from "./data"; 31 | -------------------------------------------------------------------------------- /lib/src/utils/authentication-utils.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import { PKCE_CODE_VERIFIER, PKCE_SEPARATOR } from "../constants"; 20 | import { DecodedIDTokenPayload } from "../models"; 21 | 22 | export class AuthenticationUtils { 23 | // eslint-disable-next-line @typescript-eslint/no-empty-function 24 | private constructor() {} 25 | 26 | public static filterClaimsFromIDTokenPayload(payload: DecodedIDTokenPayload): any { 27 | const optionalizedPayload: Partial = { ...payload }; 28 | 29 | delete optionalizedPayload?.iss; 30 | delete optionalizedPayload?.aud; 31 | delete optionalizedPayload?.exp; 32 | delete optionalizedPayload?.iat; 33 | delete optionalizedPayload?.acr; 34 | delete optionalizedPayload?.amr; 35 | delete optionalizedPayload?.azp; 36 | delete optionalizedPayload?.auth_time; 37 | delete optionalizedPayload?.nonce; 38 | delete optionalizedPayload?.c_hash; 39 | delete optionalizedPayload?.at_hash; 40 | delete optionalizedPayload?.nbf; 41 | delete optionalizedPayload?.isk; 42 | delete optionalizedPayload?.sid; 43 | 44 | const camelCasedPayload : any= {}; 45 | 46 | Object.entries(optionalizedPayload).forEach(([ key, value ]: [ key: string, value: unknown ]) => { 47 | const keyParts: string[] = key.split("_"); 48 | 49 | const camelCasedKey: string = keyParts 50 | .map((key: string, index: number) => { 51 | if (index === 0) { 52 | return key; 53 | } 54 | 55 | return [ key[ 0 ].toUpperCase(), ...key.slice(1) ].join(""); 56 | }) 57 | .join(""); 58 | 59 | camelCasedPayload[camelCasedKey] = value; 60 | }); 61 | 62 | return camelCasedPayload; 63 | } 64 | 65 | /** 66 | * @deprecated since v1.0.6 and will be removed with the v2.0.0 release. 67 | */ 68 | public static getTenantDomainFromIdTokenPayload = ( 69 | payload: DecodedIDTokenPayload, 70 | uidSeparator: string = "@" 71 | ): string => { 72 | // Try to extract the tenant domain from the `sub` claim. 73 | const uid: string = payload.sub; 74 | const tokens: string[] = uid.split(uidSeparator); 75 | 76 | // This works only when the email is used as the username 77 | // and the tenant domain is appended to the`sub` attribute. 78 | return tokens.length > 2 ? tokens[tokens.length - 1] : ""; 79 | }; 80 | 81 | public static getTokenRequestHeaders(): HeadersInit { 82 | return { 83 | Accept: "application/json", 84 | "Content-Type": "application/x-www-form-urlencoded" 85 | }; 86 | } 87 | 88 | /** 89 | * This generates the state param value to be sent with an authorization request. 90 | * 91 | * @param pkceKey - The PKCE key. 92 | * @param state - The state value to be passed. (The correlation ID will be appended to this state value.) 93 | * 94 | * @returns The state param value. 95 | */ 96 | public static generateStateParamForRequestCorrelation(pkceKey: string, state?: string): string { 97 | const index: number = parseInt(pkceKey.split(PKCE_SEPARATOR)[1]); 98 | 99 | return state ? `${state}_request_${index}` : `request_${index}`; 100 | } 101 | 102 | public static extractPKCEKeyFromStateParam(stateParam: string): string { 103 | const index: number = parseInt(stateParam.split("request_")[1]); 104 | 105 | return `${PKCE_CODE_VERIFIER}${PKCE_SEPARATOR}${index}`; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /lib/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | export * from "./authentication-utils"; 20 | -------------------------------------------------------------------------------- /lib/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true, 4 | "target": "es6", 5 | "module": "esnext", 6 | "moduleResolution": "node", 7 | "noImplicitAny": false, 8 | "jsx": "react", 9 | "resolveJsonModule": true, 10 | "sourceMap": true, 11 | "noLib": false, 12 | "suppressImplicitAnyIndexErrors": true, 13 | "experimentalDecorators": true, 14 | "composite": true, 15 | "declarationMap": true, 16 | "baseUrl": "/", 17 | "strict": true, 18 | "paths": { 19 | "*": ["types/*"] 20 | }, 21 | "outDir": "./dist", 22 | "forceConsistentCasingInFileNames": true 23 | }, 24 | "compileOnSave": false, 25 | "exclude": ["node_modules", "test-configs", "src/**/tests/*", "**/*.test.ts", "dist/**/*"] 26 | } 27 | -------------------------------------------------------------------------------- /lib/tsdoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", 3 | "tagDefinitions": [ 4 | { 5 | "tagName": "@preserve", 6 | "syntaxKind": "block" 7 | } 8 | ], 9 | "supportForTags": { 10 | "@preserve": true, 11 | "@example": true, 12 | "@returns": true, 13 | "@deprecated": true, 14 | "@param": true, 15 | "@throws": true, 16 | "@link": true 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "asgardeo-auth-js-sdk", 3 | "description": "Asgardeo Auth JavaScript SDK and Sample Apps", 4 | "main": "index.js", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1", 7 | "build": "lerna run build --stream", 8 | "build:dev": "lerna run build:dev --stream", 9 | "prebuild": "yarn run bootstrap", 10 | "bootstrap": "yarn install && lerna bootstrap", 11 | "remove-node-modules": "npx lerna exec -- rimraf -rf node_modules && rimraf -rf node_modules", 12 | "remove-package-lock": "npx lerna exec -- rimraf -rf yarn.lock && rimraf -rf yarn.lock", 13 | "lint": "lerna run lint", 14 | "fix-lint": "lerna run fix-lint", 15 | "clean": "lerna run clean --stream", 16 | "clean-all": "yarn run remove-package-lock && npm run remove-node-modules", 17 | "bump-patch-version": "lerna version patch --yes", 18 | "bump-minor-version": "lerna version minor --yes", 19 | "bump-major-version": "lerna version major --yes" 20 | }, 21 | "repository": { 22 | "type": "git", 23 | "url": "git+https://github.com/asgardeo/asgardeo-auth-js-sdk.git" 24 | }, 25 | "keywords": [ 26 | "Asgardeo", 27 | "OIDC", 28 | "OAuth2", 29 | "Authentication", 30 | "Authorization" 31 | ], 32 | "author": "Asgardeo", 33 | "license": "Apache-2.0", 34 | "bugs": { 35 | "url": "https://github.com/asgardeo/asgardeo-auth-js-sdk/issues" 36 | }, 37 | "homepage": "https://github.com/asgardeo/asgardeo-auth-js-sdk#readme", 38 | "devDependencies": { 39 | "@typescript-eslint/eslint-plugin": "^5.13.0", 40 | "@typescript-eslint/parser": "^5.13.0", 41 | "cross-env": "^7.0.3", 42 | "eslint": "^8.10.0", 43 | "eslint-plugin-header": "^3.1.1", 44 | "eslint-plugin-import": "^2.25.4", 45 | "eslint-plugin-tsdoc": "^0.2.17", 46 | "lerna": "^4.0.0", 47 | "rimraf": "^3.0.2", 48 | "typescript": "~4.5.5" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /pull_request_template.md: -------------------------------------------------------------------------------- 1 | ### Purpose 2 | 3 | 4 | ### Related Issues 5 | - 6 | 7 | ### Related PRs 8 | - 9 | 10 | ### Checklist 11 | - [ ] Manual test round performed and verified. 12 | - [ ] UX/UI review done on the final implementation. 13 | - [ ] Documentation provided. (Add links if there are any) 14 | - [ ] Unit tests provided. (Add links if there are any) 15 | 16 | ### Security checks 17 | - [ ] Followed secure coding standards in http://wso2.com/technical-reports/wso2-secure-engineering-guidelines? 18 | - [ ] Confirmed that this PR doesn't commit any keys, passwords, tokens, usernames, or other secrets? 19 | --------------------------------------------------------------------------------