├── .gitattributes
├── ballerina
├── icon.png
├── tests
│ ├── resources
│ │ ├── keystore
│ │ │ ├── ballerinaKeystore.p12
│ │ │ └── ballerinaTruststore.p12
│ │ ├── cert
│ │ │ ├── invalidPublic.crt
│ │ │ └── public.crt
│ │ └── key
│ │ │ ├── private.key
│ │ │ └── encryptedPrivate.key
│ ├── client_self_signed_jwt_auth_provider_test.bal
│ ├── listener_jwt_auth_provider_test.bal
│ └── test_utils.bal
├── CompilerPlugin.toml
├── Ballerina.toml
├── init.bal
├── jwt_errors.bal
├── client_self_signed_jwt_auth_provider.bal
├── README.md
├── jwt_commons.bal
├── Dependencies.toml
├── listener_jwt_auth_provider.bal
├── build.gradle
└── jwt_issuer.bal
├── examples
└── order-management-service
│ ├── .github
│ └── Readme.md
│ ├── sts
│ ├── Ballerina.toml
│ ├── resources
│ │ ├── public.crt
│ │ └── private.key
│ └── sts.bal
│ ├── order-management-service.png
│ ├── order_service
│ ├── Ballerina.toml
│ ├── resources
│ │ ├── public.crt
│ │ └── private.key
│ ├── modules
│ │ └── representations
│ │ │ └── representations.bal
│ └── order_service.bal
│ └── inventory_service
│ ├── Ballerina.toml
│ ├── modules
│ ├── representations
│ │ └── representations.bal
│ └── inventory
│ │ └── inventory.bal
│ ├── resources
│ ├── public.crt
│ └── private.key
│ └── inventory_service.bal
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── load-tests
└── order_management_service
│ ├── deployment
│ ├── kustomization.yaml
│ └── ingress.yaml
│ ├── src
│ ├── Ballerina.toml
│ ├── Cloud.toml
│ ├── resources
│ │ ├── sts
│ │ │ ├── public.crt
│ │ │ └── private.key
│ │ └── order_service
│ │ │ ├── public.crt
│ │ │ └── private.key
│ ├── order_service.bal
│ └── sts.bal
│ └── scripts
│ ├── run.sh
│ └── http-post-request.jmx
├── codecov.yml
├── compiler-plugin
├── src
│ └── main
│ │ ├── resources
│ │ └── rules.json
│ │ └── java
│ │ ├── module-info.java
│ │ └── io
│ │ └── ballerina
│ │ └── stdlib
│ │ └── jwt
│ │ └── compiler
│ │ ├── staticcodeanalyzer
│ │ ├── RuleFactory.java
│ │ ├── JwtCodeAnalyzer.java
│ │ ├── RuleImpl.java
│ │ └── JwtRule.java
│ │ └── JwtCompilerPlugin.java
└── build.gradle
├── .github
├── pull_request_template.md
├── CODEOWNERS
└── workflows
│ ├── trivy-scan.yml
│ ├── publish-release.yml
│ ├── build-timestamped-master.yml
│ ├── fossa_scan.yml
│ ├── pull-request.yml
│ ├── process-load-test-result.yml
│ ├── central-publish.yml
│ ├── trigger-load-tests.yml
│ ├── build-with-bal-test-graalvm.yml
│ └── update_specs.yml
├── compiler-plugin-tests
├── src
│ └── test
│ │ ├── resources
│ │ ├── static_code_analyzer
│ │ │ └── ballerina_packages
│ │ │ │ └── rule1
│ │ │ │ ├── Ballerina.toml
│ │ │ │ ├── inline_pos_arg.bal
│ │ │ │ ├── inline_named_arg.bal
│ │ │ │ ├── function_pos_arg_capture_pattern.bal
│ │ │ │ ├── function_named_arg_capture_pattern.bal
│ │ │ │ ├── module_pos_arg_capture_pattern.bal
│ │ │ │ ├── module_named_arg_capture_pattern.bal
│ │ │ │ ├── function_pos_arg_list_pattern.bal
│ │ │ │ ├── module_pos_arg_list_pattern.bal
│ │ │ │ ├── function_named_arg_list_pattern.bal
│ │ │ │ └── module_named_arg_list_pattern.bal
│ │ └── testng.xml
│ │ └── java
│ │ └── io
│ │ └── ballerina
│ │ └── stdlib
│ │ └── jwt
│ │ └── compiler
│ │ └── staticcodeanalyzer
│ │ └── StaticCodeAnalyzerTest.java
└── build.gradle
├── .gitignore
├── gradle.properties
├── native
├── src
│ └── main
│ │ └── java
│ │ ├── module-info.java
│ │ └── io
│ │ └── ballerina
│ │ └── stdlib
│ │ └── jwt
│ │ ├── ModuleUtils.java
│ │ ├── JwtUtils.java
│ │ └── JwtConstants.java
└── build.gradle
├── settings.gradle
├── changelog.md
├── gradlew.bat
├── docs
└── proposals
│ └── enable-crypto-key-usage.md
├── README.md
├── gradlew
└── LICENSE
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Ensure all Java files use LF.
2 | *.java eol=lf
3 |
--------------------------------------------------------------------------------
/ballerina/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ballerina-platform/module-ballerina-jwt/HEAD/ballerina/icon.png
--------------------------------------------------------------------------------
/examples/order-management-service/.github/Readme.md:
--------------------------------------------------------------------------------
1 | ../../order-management-service/A Guide on Securing Ballerina Rest APIs with JWT Auth.md
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ballerina-platform/module-ballerina-jwt/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/load-tests/order_management_service/deployment/kustomization.yaml:
--------------------------------------------------------------------------------
1 | resources:
2 | - order_management_service.yaml
3 | - ingress.yaml
4 |
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | coverage:
2 | precision: 2
3 | round: down
4 | range: "60...80"
5 | status:
6 | project:
7 | default:
8 | target: 80
9 |
--------------------------------------------------------------------------------
/examples/order-management-service/sts/Ballerina.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | org = "jwt"
3 | name = "sts"
4 | version = "1.0.0"
5 |
6 | [build-options]
7 | observabilityIncluded = true
8 |
--------------------------------------------------------------------------------
/ballerina/tests/resources/keystore/ballerinaKeystore.p12:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ballerina-platform/module-ballerina-jwt/HEAD/ballerina/tests/resources/keystore/ballerinaKeystore.p12
--------------------------------------------------------------------------------
/ballerina/tests/resources/keystore/ballerinaTruststore.p12:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ballerina-platform/module-ballerina-jwt/HEAD/ballerina/tests/resources/keystore/ballerinaTruststore.p12
--------------------------------------------------------------------------------
/examples/order-management-service/order-management-service.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ballerina-platform/module-ballerina-jwt/HEAD/examples/order-management-service/order-management-service.png
--------------------------------------------------------------------------------
/examples/order-management-service/order_service/Ballerina.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | org = "jwt"
3 | name = "order_service"
4 | version = "1.0.0"
5 |
6 | [build-options]
7 | observabilityIncluded = true
8 |
--------------------------------------------------------------------------------
/examples/order-management-service/inventory_service/Ballerina.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | org = "jwt"
3 | name = "inventory_service"
4 | version = "1.0.0"
5 |
6 | [build-options]
7 | observabilityIncluded = true
8 |
--------------------------------------------------------------------------------
/compiler-plugin/src/main/resources/rules.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": 1,
4 | "kind": "VULNERABILITY",
5 | "description": "Avoid using weak cipher algorithms when signing and verifying JWTs"
6 | }
7 | ]
8 |
--------------------------------------------------------------------------------
/load-tests/order_management_service/src/Ballerina.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | org = "jwt"
3 | name = "order_management_service"
4 | version = "1.0.0"
5 |
6 | [build-options]
7 | observabilityIncluded = false
8 | cloud = "k8s"
9 |
--------------------------------------------------------------------------------
/ballerina/CompilerPlugin.toml:
--------------------------------------------------------------------------------
1 | [plugin]
2 | id = "jwt-compiler-plugin"
3 | class = "io.ballerina.stdlib.jwt.compiler.JwtCompilerPlugin"
4 |
5 | [[dependency]]
6 | path = "../compiler-plugin/build/libs/jwt-compiler-plugin-2.15.1.jar"
7 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | ## Purpose
2 |
3 | ## Examples
4 |
5 | ## Checklist
6 | - [ ] Linked to an issue
7 | - [ ] Updated the changelog
8 | - [ ] Added tests
9 | - [ ] Updated the spec
10 | - [ ] Checked native-image compatibility
11 |
--------------------------------------------------------------------------------
/compiler-plugin-tests/src/test/resources/static_code_analyzer/ballerina_packages/rule1/Ballerina.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | org = "wso2"
3 | name = "rule1"
4 | version = "0.1.0"
5 | distribution = "2201.12.3"
6 |
7 | [build-options]
8 | observabilityIncluded = true
9 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # Lines starting with '#' are comments.
2 | # Each line is a file pattern followed by one or more owners.
3 |
4 | # See: https://help.github.com/articles/about-codeowners/
5 |
6 | # These owners will be the default owners for everything in the repo.
7 | * @NipunaRanasinghe @ayeshLK @Nuvindu @shafreenAnfar
8 |
--------------------------------------------------------------------------------
/load-tests/order_management_service/src/Cloud.toml:
--------------------------------------------------------------------------------
1 | [container.image]
2 | repository="ballerina"
3 | name="order_management_service"
4 |
5 | [cloud.deployment]
6 | min_memory="256Mi"
7 | max_memory="512Mi"
8 | min_cpu="200m"
9 | max_cpu="1000m"
10 |
11 | [cloud.deployment.autoscaling]
12 | min_replicas=1
13 | max_replicas=1
14 |
--------------------------------------------------------------------------------
/.github/workflows/trivy-scan.yml:
--------------------------------------------------------------------------------
1 | name: Trivy
2 |
3 | on:
4 | workflow_dispatch:
5 | schedule:
6 | - cron: "30 20 * * *"
7 |
8 | jobs:
9 | call_workflow:
10 | name: Run Trivy Scan Workflow
11 | if: ${{ github.repository_owner == 'ballerina-platform' }}
12 | uses: ballerina-platform/ballerina-library/.github/workflows/trivy-scan-template.yml@main
13 | secrets: inherit
14 |
--------------------------------------------------------------------------------
/.github/workflows/publish-release.yml:
--------------------------------------------------------------------------------
1 | name: Publish Release
2 |
3 | on:
4 | workflow_dispatch:
5 | repository_dispatch:
6 | types: [stdlib-release-pipeline]
7 |
8 | jobs:
9 | call_workflow:
10 | name: Run Release Workflow
11 | if: ${{ github.repository_owner == 'ballerina-platform' }}
12 | uses: ballerina-platform/ballerina-library/.github/workflows/release-package-template.yml@main
13 | secrets: inherit
14 | with:
15 | package-name: jwt
16 | package-org: ballerina
17 |
--------------------------------------------------------------------------------
/.github/workflows/build-timestamped-master.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | paths-ignore:
8 | - "*.md"
9 | - "docs/**"
10 | - "load-tests/**"
11 | workflow_dispatch:
12 |
13 | jobs:
14 | call_workflow:
15 | name: Run Build Workflow
16 | if: ${{ github.repository_owner == 'ballerina-platform' }}
17 | uses: ballerina-platform/ballerina-library/.github/workflows/build-timestamp-master-template.yml@main
18 | secrets: inherit
19 |
--------------------------------------------------------------------------------
/.github/workflows/fossa_scan.yml:
--------------------------------------------------------------------------------
1 | name: Fossa Scan
2 | on:
3 | workflow_dispatch:
4 | schedule:
5 | - cron: '30 18 * * *' # 00:00 in LK time (GMT+5:30)
6 | jobs:
7 | fossa-scan:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v3
11 | - uses: fossas/fossa-action@main
12 | env:
13 | packageUser: ${{ secrets.BALLERINA_BOT_USERNAME }}
14 | packagePAT: ${{ secrets.BALLERINA_BOT_TOKEN }}
15 | with:
16 | api-key: ${{secrets.FOSSA_APIKEY}}
17 |
--------------------------------------------------------------------------------
/.github/workflows/pull-request.yml:
--------------------------------------------------------------------------------
1 | name: PR Build
2 |
3 | concurrency:
4 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
5 | cancel-in-progress: true
6 |
7 | on: [pull_request]
8 |
9 | jobs:
10 | call_workflow:
11 | name: Run PR Build Workflow
12 | if: ${{ github.repository_owner == 'ballerina-platform' }}
13 | uses: ballerina-platform/ballerina-library/.github/workflows/pull-request-build-template.yml@main
14 | with:
15 | additional-windows-test-flags: "-Pdisable=jwks"
16 | secrets: inherit
17 |
--------------------------------------------------------------------------------
/ballerina/Ballerina.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | org = "ballerina"
3 | name = "jwt"
4 | version = "2.15.1"
5 | authors = ["Ballerina"]
6 | keywords = ["security", "authentication", "jwt", "jwk", "jws"]
7 | repository = "https://github.com/ballerina-platform/module-ballerina-jwt"
8 | icon = "icon.png"
9 | license = ["Apache-2.0"]
10 | distribution = "2201.12.0"
11 |
12 | [platform.java21]
13 | graalvmCompatible = true
14 |
15 | [[platform.java21.dependency]]
16 | groupId = "io.ballerina.stdlib"
17 | artifactId = "jwt-native"
18 | version = "2.15.1"
19 | path = "../native/build/libs/jwt-native-2.15.1.jar"
20 |
--------------------------------------------------------------------------------
/.github/workflows/process-load-test-result.yml:
--------------------------------------------------------------------------------
1 | name: Process load test results
2 |
3 | on:
4 | repository_dispatch:
5 | types: [jwt-load-test]
6 |
7 | jobs:
8 | call_stdlib_process_load_test_results_workflow:
9 | name: Run StdLib Process Load Test Results Workflow
10 | uses: ballerina-platform/ballerina-library/.github/workflows/process-load-test-results-template.yml@main
11 | with:
12 | results: ${{ toJson(github.event.client_payload.results) }}
13 | secrets:
14 | ballerina_bot_token: ${{ secrets.BALLERINA_BOT_TOKEN }}
15 | ballerina_reviewer_bot_token: ${{ secrets.BALLERINA_REVIEWER_BOT_TOKEN }}
16 |
--------------------------------------------------------------------------------
/.github/workflows/central-publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish to the Ballerina central
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | environment:
7 | type: choice
8 | description: Select Environment
9 | required: true
10 | options:
11 | - DEV CENTRAL
12 | - STAGE CENTRAL
13 |
14 | jobs:
15 | call_workflow:
16 | name: Run Central Publish Workflow
17 | if: ${{ github.repository_owner == 'ballerina-platform' }}
18 | uses: ballerina-platform/ballerina-library/.github/workflows/central-publish-template.yml@main
19 | secrets: inherit
20 | with:
21 | environment: ${{ github.event.inputs.environment }}
22 |
--------------------------------------------------------------------------------
/load-tests/order_management_service/deployment/ingress.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: networking.k8s.io/v1
3 | kind: Ingress
4 | metadata:
5 | name: order-management-service
6 | annotations:
7 | kubernetes.io/ingress.class: nginx
8 | nginx.ingress.kubernetes.io/ssl-passthrough: "true"
9 | nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
10 | spec:
11 | rules:
12 | - host: bal.perf.test
13 | http:
14 | paths:
15 | - path: "/"
16 | pathType: Prefix
17 | backend:
18 | service:
19 | name: order-managemen
20 | port:
21 | number: 9090
22 | tls:
23 | - hosts:
24 | - "bal.perf.test"
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled class file
2 | *.class
3 |
4 | # Log file
5 | *.log
6 |
7 | # BlueJ files
8 | *.ctxt
9 |
10 | # Mobile Tools for Java (J2ME)
11 | .mtj.tmp/
12 |
13 | # Package Files #
14 | *.jar
15 | *.war
16 | *.nar
17 | *.ear
18 | *.zip
19 | *.tar.gz
20 | *.rar
21 |
22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
23 | hs_err_pid*
24 |
25 | build
26 | .gradle/
27 | target
28 | # IDEA Files
29 | .idea/
30 | *.iml
31 | *.ipr
32 | *.iws
33 |
34 | # MacOS
35 | *.DS_Store
36 |
37 | # Ballerina
38 | velocity.log*
39 | *Ballerina.lock
40 |
41 | # Auto generated Dependencies.toml files
42 | examples/**/Dependencies.toml
43 | load-tests/**/Dependencies.toml
44 |
45 | compiler-plugin-tests/**/target
46 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.caching=true
2 | group=io.ballerina.stdlib
3 | version=2.15.2-SNAPSHOT
4 | ballerinaLangVersion=2201.12.0
5 | testngVersion=7.6.1
6 |
7 | checkstylePluginVersion=10.12.0
8 | ballerinaGradlePluginVersion=2.3.0
9 | shadowJarPluginVersion=8.1.1
10 | downloadPluginVersion=5.4.0
11 | releasePluginVersion=2.8.0
12 | spotbugsPluginVersion=6.0.18
13 | gsonVersion=2.7
14 | balScanVersion=0.10.0
15 | jacksonDatabindVersion=2.17.2
16 |
17 | stdlibCacheVersion=3.10.0
18 | stdlibCryptoVersion=2.9.0
19 | stdlibLogVersion=2.12.0
20 | stdlibTimeVersion=2.7.0
21 | # Transitive dependencies
22 | stdlibTaskVersion=2.7.0
23 | stdlibConstraintVersion=1.7.0
24 | stdlibIoVersion=1.8.0
25 | observeVersion=1.5.0
26 | observeInternalVersion=1.5.0
27 |
--------------------------------------------------------------------------------
/native/src/main/java/module-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2025 WSO2 LLC. (http://www.wso2.com).
3 | *
4 | * WSO2 Inc. 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
14 | * OF ANY KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 |
19 | module io.ballerina.stdlib.jwt {
20 | requires io.ballerina.runtime;
21 | requires java.net.http;
22 | requires io.ballerina.stdlib.crypto;
23 | exports io.ballerina.stdlib.jwt;
24 | }
25 |
--------------------------------------------------------------------------------
/ballerina/init.bal:
--------------------------------------------------------------------------------
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 | import ballerina/jballerina.java;
18 |
19 | isolated function init() {
20 | setModule();
21 | }
22 |
23 | isolated function setModule() = @java:Method {
24 | 'class: "io.ballerina.stdlib.jwt.ModuleUtils"
25 | } external;
26 |
--------------------------------------------------------------------------------
/compiler-plugin/src/main/java/module-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2025 WSO2 LLC. (http://www.wso2.com).
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
14 | * OF ANY KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 |
19 | module io.ballerina.stdlib.jwt.compiler {
20 | requires io.ballerina.lang;
21 | requires io.ballerina.tools.api;
22 | requires io.ballerina.parser;
23 | requires io.ballerina.scan;
24 | }
25 |
--------------------------------------------------------------------------------
/examples/order-management-service/inventory_service/modules/representations/representations.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2021, 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 | import ballerina/http;
18 |
19 | public type OrderItem record {|
20 | string category;
21 | string code;
22 | int qty;
23 | |};
24 |
25 | public type InventoryUpdated record {|
26 | *http:Ok;
27 | |};
28 |
--------------------------------------------------------------------------------
/compiler-plugin-tests/src/test/resources/static_code_analyzer/ballerina_packages/rule1/inline_pos_arg.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 WSO2 LLC. (http://www.wso2.com).
2 | //
3 | // WSO2 LLC. 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
13 | // OF ANY KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | import ballerina/jwt;
18 |
19 | public function inlinePosArg() returns error? {
20 | string _ = check jwt:issue({
21 | issuer: "ballerina",
22 | expTime: 3600,
23 | signatureConfig: {
24 | algorithm: jwt:NONE
25 | }
26 | });
27 | }
28 |
--------------------------------------------------------------------------------
/compiler-plugin-tests/src/test/resources/static_code_analyzer/ballerina_packages/rule1/inline_named_arg.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 WSO2 LLC. (http://www.wso2.com).
2 | //
3 | // WSO2 LLC. 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
13 | // OF ANY KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | import ballerina/jwt;
18 |
19 | public function inlineNamedArg() returns error? {
20 | string _ = check jwt:issue(issuerConfig = {
21 | issuer: "ballerina",
22 | expTime: 3600,
23 | signatureConfig: {
24 | algorithm: jwt:NONE
25 | }
26 | });
27 | }
28 |
--------------------------------------------------------------------------------
/load-tests/order_management_service/scripts/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 | # Copyright 2021 WSO2 Inc. (http://wso2.org)
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except 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, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 | # ----------------------------------------------------------------------------
17 | # Execution script for ballerina performance tests
18 | # ----------------------------------------------------------------------------
19 | set -e
20 | source base-scenario.sh
21 |
22 | jmeter -n -t "$scriptsDir/"http-post-request.jmx -l "$resultsDir/"original.jtl -Jusers="$concurrent_users" -Jduration=3600 -Jhost=bal.perf.test -Jport=443 -Jprotocol=https -Jpath=order $payload_flags
23 |
--------------------------------------------------------------------------------
/compiler-plugin-tests/src/test/resources/static_code_analyzer/ballerina_packages/rule1/function_pos_arg_capture_pattern.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 WSO2 LLC. (http://www.wso2.com).
2 | //
3 | // WSO2 LLC. 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
13 | // OF ANY KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | import ballerina/jwt;
18 |
19 | public function functionPosArgCapturePattern() returns error? {
20 | jwt:IssuerConfig issuerConfig = {
21 | issuer: "ballerina",
22 | expTime: 3600,
23 | signatureConfig: {
24 | algorithm: jwt:NONE
25 | }
26 | };
27 |
28 | string _ = check jwt:issue(issuerConfig);
29 | }
30 |
--------------------------------------------------------------------------------
/compiler-plugin-tests/src/test/resources/static_code_analyzer/ballerina_packages/rule1/function_named_arg_capture_pattern.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 WSO2 LLC. (http://www.wso2.com).
2 | //
3 | // WSO2 LLC. 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
13 | // OF ANY KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | import ballerina/jwt;
18 |
19 | public function functionNamedArgCapturePattern() returns error? {
20 | jwt:IssuerConfig issuerConfig = {
21 | issuer: "ballerina",
22 | expTime: 3600,
23 | signatureConfig: {
24 | algorithm: jwt:NONE
25 | }
26 | };
27 |
28 | string _ = check jwt:issue(issuerConfig = issuerConfig);
29 | }
30 |
--------------------------------------------------------------------------------
/compiler-plugin-tests/src/test/resources/static_code_analyzer/ballerina_packages/rule1/module_pos_arg_capture_pattern.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 WSO2 LLC. (http://www.wso2.com).
2 | //
3 | // WSO2 LLC. 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
13 | // OF ANY KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | import ballerina/jwt;
18 |
19 | jwt:IssuerConfig issuerConfigModulePosArgCapturePattern = {
20 | issuer: "ballerina",
21 | expTime: 3600,
22 | signatureConfig: {
23 | algorithm: jwt:NONE
24 | }
25 | };
26 |
27 | public function modulePosArgCapturePattern() returns error? {
28 | string _ = check jwt:issue(issuerConfigModulePosArgCapturePattern);
29 | }
30 |
--------------------------------------------------------------------------------
/compiler-plugin-tests/src/test/resources/static_code_analyzer/ballerina_packages/rule1/module_named_arg_capture_pattern.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 WSO2 LLC. (http://www.wso2.com).
2 | //
3 | // WSO2 LLC. 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
13 | // OF ANY KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | import ballerina/jwt;
18 |
19 | jwt:IssuerConfig issuerConfigModuleNamedArgCapturePattern = {
20 | issuer: "ballerina",
21 | expTime: 3600,
22 | signatureConfig: {
23 | algorithm: jwt:NONE
24 | }
25 | };
26 |
27 | public function moduleNamedArgCapturePattern() returns error? {
28 | string _ = check jwt:issue(issuerConfig = issuerConfigModuleNamedArgCapturePattern);
29 | }
30 |
--------------------------------------------------------------------------------
/compiler-plugin-tests/src/test/resources/testng.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/compiler-plugin-tests/src/test/resources/static_code_analyzer/ballerina_packages/rule1/function_pos_arg_list_pattern.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 WSO2 LLC. (http://www.wso2.com).
2 | //
3 | // WSO2 LLC. 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
13 | // OF ANY KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | import ballerina/jwt;
18 |
19 | public function functionPosArgListPattern() returns error? {
20 | [jwt:IssuerConfig] [issuerConfig] = [
21 | {
22 | issuer: "ballerina",
23 | expTime: 3600,
24 | signatureConfig: {
25 | algorithm: jwt:NONE
26 | }
27 | }
28 | ];
29 |
30 | string _ = check jwt:issue(issuerConfig);
31 | }
32 |
--------------------------------------------------------------------------------
/compiler-plugin-tests/src/test/resources/static_code_analyzer/ballerina_packages/rule1/module_pos_arg_list_pattern.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 WSO2 LLC. (http://www.wso2.com).
2 | //
3 | // WSO2 LLC. 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
13 | // OF ANY KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | import ballerina/jwt;
18 |
19 | [jwt:IssuerConfig] [issuerConfigModulePosArgListPattern] = [
20 | {
21 | issuer: "ballerina",
22 | expTime: 3600,
23 | signatureConfig: {
24 | algorithm: jwt:NONE
25 | }
26 | }
27 | ];
28 |
29 | public function modulePosArgListPattern() returns error? {
30 | string _ = check jwt:issue(issuerConfigModulePosArgListPattern);
31 | }
32 |
--------------------------------------------------------------------------------
/compiler-plugin-tests/src/test/resources/static_code_analyzer/ballerina_packages/rule1/function_named_arg_list_pattern.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 WSO2 LLC. (http://www.wso2.com).
2 | //
3 | // WSO2 LLC. 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
13 | // OF ANY KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | import ballerina/jwt;
18 |
19 | public function functionNamedArgListPattern() returns error? {
20 | [jwt:IssuerConfig] [issuerConfig] = [
21 | {
22 | issuer: "ballerina",
23 | expTime: 3600,
24 | signatureConfig: {
25 | algorithm: jwt:NONE
26 | }
27 | }
28 | ];
29 |
30 | string _ = check jwt:issue(issuerConfig = issuerConfig);
31 | }
32 |
--------------------------------------------------------------------------------
/compiler-plugin-tests/src/test/resources/static_code_analyzer/ballerina_packages/rule1/module_named_arg_list_pattern.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 WSO2 LLC. (http://www.wso2.com).
2 | //
3 | // WSO2 LLC. 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
13 | // OF ANY KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | import ballerina/jwt;
18 |
19 | [jwt:IssuerConfig] [issuerConfigModuleNamedArgListPattern] = [
20 | {
21 | issuer: "ballerina",
22 | expTime: 3600,
23 | signatureConfig: {
24 | algorithm: jwt:NONE
25 | }
26 | }
27 | ];
28 |
29 | public function moduleNamedArgListPattern() returns error? {
30 | string _ = check jwt:issue(issuerConfig = issuerConfigModuleNamedArgListPattern);
31 | }
32 |
--------------------------------------------------------------------------------
/ballerina/tests/resources/cert/invalidPublic.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDJjCCAg6gAwIBAgIIQu5yrnbBC2gwDQYJKoZIhvcNAQEFBQAwNjE0MDIGA1UE
3 | AxMrZmVkZXJhdGVkLXNpZ25vbi5zeXN0ZW0uZ3NlcnZpY2VhY2NvdW50LmNvbTAe
4 | Fw0yMTAyMDQwNDI5NDhaFw0yMTAyMjAxNjQ0NDhaMDYxNDAyBgNVBAMTK2ZlZGVy
5 | YXRlZC1zaWdub24uc3lzdGVtLmdzZXJ2aWNlYWNjb3VudC5jb20wggEiMA0GCSqG
6 | SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDeDjrDi5FgHHwJcVq5aHpznI7hrH9UO7nL
7 | yaX8l3gbHvXXXnk9N20t5G7Bk6EnqdHLxi8sU9dz9pe0eJ+dCyL1i4j++jssYba/
8 | cILGHqd1kGMh4WTESswODgQu3YNDQ+AlRBQAoKSXb+CRVX2+HejFqG/8GkiC/WS5
9 | iXJBCLklZ4XvMAibQVpn4slPbs1uwK6BxkgNCD2zO1M3Xwvf4/+RjC8CQpjZsZg1
10 | TX2osUzWBmTNxwUQNm/cvMDPupt1aTAKgrTRNRQfxM2OqYrrtvK1jOASCR8X2r2z
11 | MRDlOtEvS4WD0vFPeRJMtipg5VpQhfe5oKHBpr5tC8e42avK7uL3AgMBAAGjODA2
12 | MAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQMMAoGCCsG
13 | AQUFBwMCMA0GCSqGSIb3DQEBBQUAA4IBAQBMFTVY0njCVNoiZYcmchwkXGiAh9s3
14 | 0jNhyX/9TMDIcMUq2ozVM1kaXCWDMqcX7ifF4h7TL/gS3xi9l36AlC5C+TwAl0dX
15 | 83s6DpfHNaub46cgHed7OPjbX/pn2vwL5EQ9asRhZhjA1qcU+Kj/6MXl1AKS6bCq
16 | TkkAH65evkxIaNHUaJ/p931hbzhhOfprrIidAg56E/DTlV9Evq2P8aYX6JDzy+Qi
17 | Xu/Stepb/YTGEYDub687EwthMWU07iygj1sjSD39ms+HlF7/zvnafPKv4bNjuYk1
18 | 215clsOH3rOvNd+npd2cl3l8GnDEIGqBoY98SABAOc5Zk25Hl/PpKt18
19 | -----END CERTIFICATE-----
20 |
--------------------------------------------------------------------------------
/ballerina/jwt_errors.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2019 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 | import ballerina/log;
18 |
19 | # Represents the error type of the module. This will be returned if an error occurred while issuing/validating a JWT
20 | # or any operation related to JWT auth providers.
21 | public type Error distinct error;
22 |
23 | // Logs and prepares the `error` as a `jwt:Error`.
24 | isolated function prepareError(string message, error? err = ()) returns Error {
25 | log:printDebug(message, 'error = err);
26 | if err is error {
27 | return error Error(message, err);
28 | }
29 | return error Error(message);
30 | }
31 |
--------------------------------------------------------------------------------
/compiler-plugin/src/main/java/io/ballerina/stdlib/jwt/compiler/staticcodeanalyzer/RuleFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2025 WSO2 LLC. (http://www.wso2.com).
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
14 | * OF ANY KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 |
19 | package io.ballerina.stdlib.jwt.compiler.staticcodeanalyzer;
20 |
21 | import io.ballerina.scan.Rule;
22 | import io.ballerina.scan.RuleKind;
23 |
24 | /**
25 | * {@code RuleFactory} contains the logic to create a {@link Rule}.
26 | */
27 | public final class RuleFactory {
28 |
29 | private RuleFactory() {}
30 |
31 | public static Rule createRule(int id, String description, RuleKind kind) {
32 | return new RuleImpl(id, description, kind);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/ballerina/tests/resources/cert/public.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDdzCCAl+gAwIBAgIEfP3e8zANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQGEwJV
3 | UzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxDTALBgNVBAoT
4 | BFdTTzIxDTALBgNVBAsTBFdTTzIxEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xNzEw
5 | MjQwNTQ3NThaFw0zNzEwMTkwNTQ3NThaMGQxCzAJBgNVBAYTAlVTMQswCQYDVQQI
6 | EwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzENMAsGA1UEChMEV1NPMjENMAsG
7 | A1UECxMEV1NPMjESMBAGA1UEAxMJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
8 | AAOCAQ8AMIIBCgKCAQEAgVyi6fViVLiZKEnw59xzNi1lcYh6z9dZnug+F9gKqFIg
9 | mdcPe+qtS7gZc1jYTjWMCbx13sFLkZqNHeDUadpmtKo3TDduOl1sqM6cz3yXb6L3
10 | 4k/leh50mzIPNmaaXxd3vOQoK4OpkgO1n32mh6+tkp3sbHmfYqDQrkVK1tmYNtPJ
11 | ffSCLT+CuIhnJUJco7N0unax+ySZN67/AX++sJpqAhAIZJzrRi6ueN3RFCIxYDXS
12 | MvxrEmOdn4gOC0o1Ar9u5Bp9N52sqqGbN1x6jNKi3bfUj122Hu5e+Y9KOmfbchhQ
13 | il2P81cIi30VKgyDn5DeWEuDoYredk4+6qAZrxMw+wIDAQABozEwLzAOBgNVHQ8B
14 | Af8EBAMCBaAwHQYDVR0OBBYEFNmtrQ36j6tUGhKrfW9qWWE7KFzMMA0GCSqGSIb3
15 | DQEBCwUAA4IBAQAv3yOwgbtOu76eJMl1BCcgTFgaMUBZoUjK9Un6HGjKEgYz/YWS
16 | ZFlY/qH5rT01DWQevUZB626d5ZNdzSBZRlpsxbf9IE/ursNHwHx9ua6fB7yHUCzC
17 | 1ZMp1lvBHABi7wcA+5nbV6zQ7HDmBXFhJfbgH1iVmA1KcvDeBPSJ/scRGasZ5q2W
18 | 3IenDNrfPIUhD74tFiCiqNJO91qD/LO+++3XeZzfPh8NRKkiPX7dB8WJ3YNBuQAv
19 | gRWTISpSSXLmqMb+7MPQVgecsepZdk8CwkRLxh3RKPJMjigmCgyvkSaoDMKAYC3i
20 | YjfUTiJ57UeqoSl0IaOFJ0wfZRFh+UytlDZa
21 | -----END CERTIFICATE-----
22 |
--------------------------------------------------------------------------------
/native/src/main/java/io/ballerina/stdlib/jwt/ModuleUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. 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 | package io.ballerina.stdlib.jwt;
20 |
21 | import io.ballerina.runtime.api.Environment;
22 | import io.ballerina.runtime.api.Module;
23 |
24 | /**
25 | * Utility functions relevant to module operations.
26 | *
27 | * @since 2.0.0
28 | */
29 | public class ModuleUtils {
30 |
31 | private static Module jwtModule;
32 |
33 | private ModuleUtils() {}
34 |
35 | public static void setModule(Environment env) {
36 | jwtModule = env.getCurrentModule();
37 | }
38 |
39 | public static Module getModule() {
40 | return jwtModule;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/examples/order-management-service/sts/resources/public.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDdzCCAl+gAwIBAgIEfP3e8zANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQGEwJV
3 | UzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxDTALBgNVBAoT
4 | BFdTTzIxDTALBgNVBAsTBFdTTzIxEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xNzEw
5 | MjQwNTQ3NThaFw0zNzEwMTkwNTQ3NThaMGQxCzAJBgNVBAYTAlVTMQswCQYDVQQI
6 | EwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzENMAsGA1UEChMEV1NPMjENMAsG
7 | A1UECxMEV1NPMjESMBAGA1UEAxMJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
8 | AAOCAQ8AMIIBCgKCAQEAgVyi6fViVLiZKEnw59xzNi1lcYh6z9dZnug+F9gKqFIg
9 | mdcPe+qtS7gZc1jYTjWMCbx13sFLkZqNHeDUadpmtKo3TDduOl1sqM6cz3yXb6L3
10 | 4k/leh50mzIPNmaaXxd3vOQoK4OpkgO1n32mh6+tkp3sbHmfYqDQrkVK1tmYNtPJ
11 | ffSCLT+CuIhnJUJco7N0unax+ySZN67/AX++sJpqAhAIZJzrRi6ueN3RFCIxYDXS
12 | MvxrEmOdn4gOC0o1Ar9u5Bp9N52sqqGbN1x6jNKi3bfUj122Hu5e+Y9KOmfbchhQ
13 | il2P81cIi30VKgyDn5DeWEuDoYredk4+6qAZrxMw+wIDAQABozEwLzAOBgNVHQ8B
14 | Af8EBAMCBaAwHQYDVR0OBBYEFNmtrQ36j6tUGhKrfW9qWWE7KFzMMA0GCSqGSIb3
15 | DQEBCwUAA4IBAQAv3yOwgbtOu76eJMl1BCcgTFgaMUBZoUjK9Un6HGjKEgYz/YWS
16 | ZFlY/qH5rT01DWQevUZB626d5ZNdzSBZRlpsxbf9IE/ursNHwHx9ua6fB7yHUCzC
17 | 1ZMp1lvBHABi7wcA+5nbV6zQ7HDmBXFhJfbgH1iVmA1KcvDeBPSJ/scRGasZ5q2W
18 | 3IenDNrfPIUhD74tFiCiqNJO91qD/LO+++3XeZzfPh8NRKkiPX7dB8WJ3YNBuQAv
19 | gRWTISpSSXLmqMb+7MPQVgecsepZdk8CwkRLxh3RKPJMjigmCgyvkSaoDMKAYC3i
20 | YjfUTiJ57UeqoSl0IaOFJ0wfZRFh+UytlDZa
21 | -----END CERTIFICATE-----
22 |
--------------------------------------------------------------------------------
/load-tests/order_management_service/src/resources/sts/public.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDdzCCAl+gAwIBAgIEfP3e8zANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQGEwJV
3 | UzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxDTALBgNVBAoT
4 | BFdTTzIxDTALBgNVBAsTBFdTTzIxEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xNzEw
5 | MjQwNTQ3NThaFw0zNzEwMTkwNTQ3NThaMGQxCzAJBgNVBAYTAlVTMQswCQYDVQQI
6 | EwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzENMAsGA1UEChMEV1NPMjENMAsG
7 | A1UECxMEV1NPMjESMBAGA1UEAxMJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
8 | AAOCAQ8AMIIBCgKCAQEAgVyi6fViVLiZKEnw59xzNi1lcYh6z9dZnug+F9gKqFIg
9 | mdcPe+qtS7gZc1jYTjWMCbx13sFLkZqNHeDUadpmtKo3TDduOl1sqM6cz3yXb6L3
10 | 4k/leh50mzIPNmaaXxd3vOQoK4OpkgO1n32mh6+tkp3sbHmfYqDQrkVK1tmYNtPJ
11 | ffSCLT+CuIhnJUJco7N0unax+ySZN67/AX++sJpqAhAIZJzrRi6ueN3RFCIxYDXS
12 | MvxrEmOdn4gOC0o1Ar9u5Bp9N52sqqGbN1x6jNKi3bfUj122Hu5e+Y9KOmfbchhQ
13 | il2P81cIi30VKgyDn5DeWEuDoYredk4+6qAZrxMw+wIDAQABozEwLzAOBgNVHQ8B
14 | Af8EBAMCBaAwHQYDVR0OBBYEFNmtrQ36j6tUGhKrfW9qWWE7KFzMMA0GCSqGSIb3
15 | DQEBCwUAA4IBAQAv3yOwgbtOu76eJMl1BCcgTFgaMUBZoUjK9Un6HGjKEgYz/YWS
16 | ZFlY/qH5rT01DWQevUZB626d5ZNdzSBZRlpsxbf9IE/ursNHwHx9ua6fB7yHUCzC
17 | 1ZMp1lvBHABi7wcA+5nbV6zQ7HDmBXFhJfbgH1iVmA1KcvDeBPSJ/scRGasZ5q2W
18 | 3IenDNrfPIUhD74tFiCiqNJO91qD/LO+++3XeZzfPh8NRKkiPX7dB8WJ3YNBuQAv
19 | gRWTISpSSXLmqMb+7MPQVgecsepZdk8CwkRLxh3RKPJMjigmCgyvkSaoDMKAYC3i
20 | YjfUTiJ57UeqoSl0IaOFJ0wfZRFh+UytlDZa
21 | -----END CERTIFICATE-----
22 |
--------------------------------------------------------------------------------
/examples/order-management-service/order_service/resources/public.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDdzCCAl+gAwIBAgIEfP3e8zANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQGEwJV
3 | UzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxDTALBgNVBAoT
4 | BFdTTzIxDTALBgNVBAsTBFdTTzIxEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xNzEw
5 | MjQwNTQ3NThaFw0zNzEwMTkwNTQ3NThaMGQxCzAJBgNVBAYTAlVTMQswCQYDVQQI
6 | EwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzENMAsGA1UEChMEV1NPMjENMAsG
7 | A1UECxMEV1NPMjESMBAGA1UEAxMJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
8 | AAOCAQ8AMIIBCgKCAQEAgVyi6fViVLiZKEnw59xzNi1lcYh6z9dZnug+F9gKqFIg
9 | mdcPe+qtS7gZc1jYTjWMCbx13sFLkZqNHeDUadpmtKo3TDduOl1sqM6cz3yXb6L3
10 | 4k/leh50mzIPNmaaXxd3vOQoK4OpkgO1n32mh6+tkp3sbHmfYqDQrkVK1tmYNtPJ
11 | ffSCLT+CuIhnJUJco7N0unax+ySZN67/AX++sJpqAhAIZJzrRi6ueN3RFCIxYDXS
12 | MvxrEmOdn4gOC0o1Ar9u5Bp9N52sqqGbN1x6jNKi3bfUj122Hu5e+Y9KOmfbchhQ
13 | il2P81cIi30VKgyDn5DeWEuDoYredk4+6qAZrxMw+wIDAQABozEwLzAOBgNVHQ8B
14 | Af8EBAMCBaAwHQYDVR0OBBYEFNmtrQ36j6tUGhKrfW9qWWE7KFzMMA0GCSqGSIb3
15 | DQEBCwUAA4IBAQAv3yOwgbtOu76eJMl1BCcgTFgaMUBZoUjK9Un6HGjKEgYz/YWS
16 | ZFlY/qH5rT01DWQevUZB626d5ZNdzSBZRlpsxbf9IE/ursNHwHx9ua6fB7yHUCzC
17 | 1ZMp1lvBHABi7wcA+5nbV6zQ7HDmBXFhJfbgH1iVmA1KcvDeBPSJ/scRGasZ5q2W
18 | 3IenDNrfPIUhD74tFiCiqNJO91qD/LO+++3XeZzfPh8NRKkiPX7dB8WJ3YNBuQAv
19 | gRWTISpSSXLmqMb+7MPQVgecsepZdk8CwkRLxh3RKPJMjigmCgyvkSaoDMKAYC3i
20 | YjfUTiJ57UeqoSl0IaOFJ0wfZRFh+UytlDZa
21 | -----END CERTIFICATE-----
22 |
--------------------------------------------------------------------------------
/.github/workflows/trigger-load-tests.yml:
--------------------------------------------------------------------------------
1 | name: Trigger Load Tests
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | tests:
7 | description: >
8 | List of test names. This needs to be filled only if you want to run a specific set of tests. Example: foo,bar
9 | required: false
10 | clusterName:
11 | description: 'Cluster name'
12 | default: 'jwt-perf-cluster-test'
13 | required: false
14 | branch:
15 | description: 'Branch of the given repository'
16 | default: ''
17 | required: false
18 | schedule:
19 | - cron: '0 16 * * *'
20 |
21 | jobs:
22 | call_stdlib_trigger_load_test_workflow:
23 | name: Run StdLib Load Test Workflow
24 | if: ${{ github.event_name != 'schedule' || (github.event_name == 'schedule' && github.repository_owner == 'ballerina-platform') }}
25 | uses: ballerina-platform/ballerina-library/.github/workflows/trigger-load-tests-template.yml@main
26 | with:
27 | repo_name: 'module-ballerina-jwt'
28 | runtime_artifacts_url: 'https://api.github.com/repos/ballerina-platform/module-ballerina-jwt/actions/artifacts'
29 | dispatch_type: 'jwt-load-test'
30 | cluster_name: ${{ inputs.clusterName }}
31 | tests: ${{ inputs.tests }}
32 | branch: ${{ inputs.branch }}
33 | secrets:
34 | ballerina_bot_token: ${{ secrets.BALLERINA_BOT_TOKEN }}
35 |
--------------------------------------------------------------------------------
/examples/order-management-service/inventory_service/resources/public.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDdzCCAl+gAwIBAgIEfP3e8zANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQGEwJV
3 | UzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxDTALBgNVBAoT
4 | BFdTTzIxDTALBgNVBAsTBFdTTzIxEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xNzEw
5 | MjQwNTQ3NThaFw0zNzEwMTkwNTQ3NThaMGQxCzAJBgNVBAYTAlVTMQswCQYDVQQI
6 | EwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzENMAsGA1UEChMEV1NPMjENMAsG
7 | A1UECxMEV1NPMjESMBAGA1UEAxMJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
8 | AAOCAQ8AMIIBCgKCAQEAgVyi6fViVLiZKEnw59xzNi1lcYh6z9dZnug+F9gKqFIg
9 | mdcPe+qtS7gZc1jYTjWMCbx13sFLkZqNHeDUadpmtKo3TDduOl1sqM6cz3yXb6L3
10 | 4k/leh50mzIPNmaaXxd3vOQoK4OpkgO1n32mh6+tkp3sbHmfYqDQrkVK1tmYNtPJ
11 | ffSCLT+CuIhnJUJco7N0unax+ySZN67/AX++sJpqAhAIZJzrRi6ueN3RFCIxYDXS
12 | MvxrEmOdn4gOC0o1Ar9u5Bp9N52sqqGbN1x6jNKi3bfUj122Hu5e+Y9KOmfbchhQ
13 | il2P81cIi30VKgyDn5DeWEuDoYredk4+6qAZrxMw+wIDAQABozEwLzAOBgNVHQ8B
14 | Af8EBAMCBaAwHQYDVR0OBBYEFNmtrQ36j6tUGhKrfW9qWWE7KFzMMA0GCSqGSIb3
15 | DQEBCwUAA4IBAQAv3yOwgbtOu76eJMl1BCcgTFgaMUBZoUjK9Un6HGjKEgYz/YWS
16 | ZFlY/qH5rT01DWQevUZB626d5ZNdzSBZRlpsxbf9IE/ursNHwHx9ua6fB7yHUCzC
17 | 1ZMp1lvBHABi7wcA+5nbV6zQ7HDmBXFhJfbgH1iVmA1KcvDeBPSJ/scRGasZ5q2W
18 | 3IenDNrfPIUhD74tFiCiqNJO91qD/LO+++3XeZzfPh8NRKkiPX7dB8WJ3YNBuQAv
19 | gRWTISpSSXLmqMb+7MPQVgecsepZdk8CwkRLxh3RKPJMjigmCgyvkSaoDMKAYC3i
20 | YjfUTiJ57UeqoSl0IaOFJ0wfZRFh+UytlDZa
21 | -----END CERTIFICATE-----
22 |
--------------------------------------------------------------------------------
/load-tests/order_management_service/src/resources/order_service/public.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDdzCCAl+gAwIBAgIEfP3e8zANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQGEwJV
3 | UzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxDTALBgNVBAoT
4 | BFdTTzIxDTALBgNVBAsTBFdTTzIxEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xNzEw
5 | MjQwNTQ3NThaFw0zNzEwMTkwNTQ3NThaMGQxCzAJBgNVBAYTAlVTMQswCQYDVQQI
6 | EwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzENMAsGA1UEChMEV1NPMjENMAsG
7 | A1UECxMEV1NPMjESMBAGA1UEAxMJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
8 | AAOCAQ8AMIIBCgKCAQEAgVyi6fViVLiZKEnw59xzNi1lcYh6z9dZnug+F9gKqFIg
9 | mdcPe+qtS7gZc1jYTjWMCbx13sFLkZqNHeDUadpmtKo3TDduOl1sqM6cz3yXb6L3
10 | 4k/leh50mzIPNmaaXxd3vOQoK4OpkgO1n32mh6+tkp3sbHmfYqDQrkVK1tmYNtPJ
11 | ffSCLT+CuIhnJUJco7N0unax+ySZN67/AX++sJpqAhAIZJzrRi6ueN3RFCIxYDXS
12 | MvxrEmOdn4gOC0o1Ar9u5Bp9N52sqqGbN1x6jNKi3bfUj122Hu5e+Y9KOmfbchhQ
13 | il2P81cIi30VKgyDn5DeWEuDoYredk4+6qAZrxMw+wIDAQABozEwLzAOBgNVHQ8B
14 | Af8EBAMCBaAwHQYDVR0OBBYEFNmtrQ36j6tUGhKrfW9qWWE7KFzMMA0GCSqGSIb3
15 | DQEBCwUAA4IBAQAv3yOwgbtOu76eJMl1BCcgTFgaMUBZoUjK9Un6HGjKEgYz/YWS
16 | ZFlY/qH5rT01DWQevUZB626d5ZNdzSBZRlpsxbf9IE/ursNHwHx9ua6fB7yHUCzC
17 | 1ZMp1lvBHABi7wcA+5nbV6zQ7HDmBXFhJfbgH1iVmA1KcvDeBPSJ/scRGasZ5q2W
18 | 3IenDNrfPIUhD74tFiCiqNJO91qD/LO+++3XeZzfPh8NRKkiPX7dB8WJ3YNBuQAv
19 | gRWTISpSSXLmqMb+7MPQVgecsepZdk8CwkRLxh3RKPJMjigmCgyvkSaoDMKAYC3i
20 | YjfUTiJ57UeqoSl0IaOFJ0wfZRFh+UytlDZa
21 | -----END CERTIFICATE-----
22 |
--------------------------------------------------------------------------------
/examples/order-management-service/order_service/modules/representations/representations.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2021, 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 | import ballerina/http;
18 |
19 | public type OrderItem record {|
20 | string category;
21 | string code;
22 | int qty;
23 | |};
24 |
25 | public type Order record {|
26 | string id;
27 | string name;
28 | OrderItem[] items;
29 | |};
30 |
31 | public type UpdateOrder record {|
32 | string name;
33 | OrderItem[] items;
34 | |};
35 |
36 | public type OrderCreated record {|
37 | *http:Created;
38 | |};
39 |
40 | public type OrderUpdated record {|
41 | *http:Ok;
42 | |};
43 |
44 | public type OrderNotFound record {|
45 | *http:BadRequest;
46 | |};
47 |
48 | public type OrderCanceled record {|
49 | *http:Ok;
50 | |};
51 |
52 | public enum InventoryOperation {
53 | INCREASE = "increase",
54 | DECREASE = "decrease"
55 | }
56 |
--------------------------------------------------------------------------------
/compiler-plugin/src/main/java/io/ballerina/stdlib/jwt/compiler/staticcodeanalyzer/JwtCodeAnalyzer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2025 WSO2 LLC. (http://www.wso2.com).
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
14 | * OF ANY KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 |
19 | package io.ballerina.stdlib.jwt.compiler.staticcodeanalyzer;
20 |
21 | import io.ballerina.compiler.syntax.tree.SyntaxKind;
22 | import io.ballerina.projects.plugins.CodeAnalysisContext;
23 | import io.ballerina.projects.plugins.CodeAnalyzer;
24 | import io.ballerina.scan.Reporter;
25 |
26 | public class JwtCodeAnalyzer extends CodeAnalyzer {
27 | private final Reporter reporter;
28 |
29 | public JwtCodeAnalyzer(Reporter reporter) {
30 | this.reporter = reporter;
31 | }
32 |
33 | @Override
34 | public void init(CodeAnalysisContext codeAnalysisContext) {
35 | codeAnalysisContext.addSyntaxNodeAnalysisTask(
36 | new JwtCipherAlgorithmAnalyzer(reporter),
37 | SyntaxKind.FUNCTION_CALL
38 | );
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/.github/workflows/build-with-bal-test-graalvm.yml:
--------------------------------------------------------------------------------
1 | name: GraalVM Check
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | lang_tag:
7 | description: Branch/Release Tag of the Ballerina Lang
8 | required: true
9 | default: master
10 | lang_version:
11 | description: Ballerina Lang Version (If given ballerina lang buid will be skipped)
12 | required: false
13 | default: ''
14 | native_image_options:
15 | description: Default native-image options
16 | required: false
17 | default: ''
18 | schedule:
19 | - cron: '30 18 * * *'
20 | pull_request:
21 | branches:
22 | - master
23 | types: [ opened, synchronize, reopened, labeled, unlabeled ]
24 |
25 | concurrency:
26 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
27 | cancel-in-progress: true
28 |
29 | jobs:
30 | call_stdlib_workflow:
31 | name: Run StdLib Workflow
32 | if: ${{ github.event_name != 'schedule' || (github.event_name == 'schedule' && github.repository_owner == 'ballerina-platform') }}
33 | uses: ballerina-platform/ballerina-library/.github/workflows/build-with-bal-test-graalvm-template.yml@main
34 | with:
35 | lang_tag: ${{ inputs.lang_tag }}
36 | lang_version: ${{ inputs.lang_version }}
37 | native_image_options: ${{ inputs.native_image_options }}
38 | additional_windows_build_flags: '-Pdisable=jwks'
39 |
--------------------------------------------------------------------------------
/.github/workflows/update_specs.yml:
--------------------------------------------------------------------------------
1 | name: Update Specifications
2 |
3 | env:
4 | SPEC_FOLDER_PATH: 'docs/spec'
5 |
6 | on:
7 | workflow_dispatch:
8 | push:
9 | branches:
10 | - master
11 | paths:
12 | - 'docs/spec/**'
13 |
14 | jobs:
15 | update_specs:
16 | name: Update Specifications
17 | if: github.repository_owner == 'ballerina-platform'
18 | runs-on: ubuntu-latest
19 |
20 | steps:
21 | - name: Checkout Repository
22 | uses: actions/checkout@v3
23 |
24 | - name: Get current date
25 | id: date
26 | run: echo "::set-output name=date::$(date +'%Y-%m-%d')"
27 |
28 | - name: Get Repo Name
29 | id: repo_name
30 | run: |
31 | MODULE=${{ github.event.repository.name }}
32 | echo "::set-output name=short_name::${MODULE##*-}"
33 |
34 | - name: Trigger Workflow
35 | run: |
36 | curl --request POST \
37 | 'https://api.github.com/repos/ballerina-platform/ballerina-dev-website/dispatches' \
38 | -H 'Accept: application/vnd.github.v3+json' \
39 | -H 'Authorization: Bearer ${{ secrets.BALLERINA_BOT_TOKEN }}' \
40 | --data "{
41 | \"event_type\": \"update-stdlib-specs\",
42 | \"client_payload\": {
43 | \"module_name\": \"${{ github.event.repository.name }}\",
44 | \"short_name\": \"${{ steps.repo_name.outputs.short_name }}\",
45 | \"file_dir\": \"${{ github.event.repository.name }}/${{ env.SPEC_FOLDER_PATH }}\",
46 | \"release_date\": \"${{ steps.date.outputs.date }}\"
47 | }
48 | }"
49 |
--------------------------------------------------------------------------------
/compiler-plugin/src/main/java/io/ballerina/stdlib/jwt/compiler/JwtCompilerPlugin.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2025 WSO2 LLC. (http://www.wso2.com).
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
14 | * OF ANY KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 |
19 | package io.ballerina.stdlib.jwt.compiler;
20 |
21 | import io.ballerina.projects.plugins.CompilerPlugin;
22 | import io.ballerina.projects.plugins.CompilerPluginContext;
23 | import io.ballerina.scan.ScannerContext;
24 | import io.ballerina.stdlib.jwt.compiler.staticcodeanalyzer.JwtCodeAnalyzer;
25 |
26 | /**
27 | * jwt compiler plugin.
28 | *
29 | * @since 2.15.1
30 | */
31 | public class JwtCompilerPlugin extends CompilerPlugin {
32 |
33 | private static final String SCANNER_CONTEXT = "ScannerContext";
34 |
35 | @Override
36 | public void init(CompilerPluginContext context) {
37 | Object object = context.userData().get(SCANNER_CONTEXT);
38 | if (object instanceof ScannerContext scannerContext) {
39 | context.addCodeAnalyzer(new JwtCodeAnalyzer(scannerContext.getReporter()));
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/compiler-plugin/src/main/java/io/ballerina/stdlib/jwt/compiler/staticcodeanalyzer/RuleImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2025 WSO2 LLC. (http://www.wso2.com).
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
14 | * OF ANY KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 |
19 | package io.ballerina.stdlib.jwt.compiler.staticcodeanalyzer;
20 |
21 | import io.ballerina.scan.Rule;
22 | import io.ballerina.scan.RuleKind;
23 |
24 | public class RuleImpl implements Rule {
25 | private final int id;
26 | private final String description;
27 | private final RuleKind kind;
28 |
29 | RuleImpl(int id, String description, RuleKind kind) {
30 | this.id = id;
31 | this.description = description;
32 | this.kind = kind;
33 | }
34 |
35 | @Override
36 | public String id() {
37 | return Integer.toString(this.id);
38 | }
39 |
40 | @Override
41 | public int numericId() {
42 | return this.id;
43 | }
44 |
45 | @Override
46 | public String description() {
47 | return this.description;
48 | }
49 |
50 | @Override
51 | public RuleKind kind() {
52 | return this.kind;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/ballerina/tests/client_self_signed_jwt_auth_provider_test.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 | // NOTE: All the tokens/credentials used in this test are dummy tokens/credentials and used only for testing purposes.
18 |
19 | import ballerina/test;
20 |
21 | @test:Config {}
22 | isolated function testClientJwtAuthProviderSuccess() returns Error? {
23 | IssuerConfig jwtConfig = {
24 | username: "admin",
25 | issuer: "wso2",
26 | audience: ["ballerina"],
27 | signatureConfig: {
28 | config: {
29 | keyStore: {
30 | path: KEYSTORE_PATH,
31 | password: "ballerina"
32 | },
33 | keyAlias: "ballerina",
34 | keyPassword: "ballerina"
35 | }
36 | }
37 | };
38 | ClientSelfSignedJwtAuthProvider jwtAuthProvider = new(jwtConfig);
39 | string result = check jwtAuthProvider.generateToken();
40 | test:assertTrue(result.startsWith("eyJhbGciOiJSUzI1NiIsICJ0eXAiOiJKV1QifQ"));
41 | }
42 |
--------------------------------------------------------------------------------
/compiler-plugin/src/main/java/io/ballerina/stdlib/jwt/compiler/staticcodeanalyzer/JwtRule.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2025 WSO2 LLC. (http://www.wso2.com).
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
14 | * OF ANY KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 |
19 | package io.ballerina.stdlib.jwt.compiler.staticcodeanalyzer;
20 |
21 | import io.ballerina.scan.Rule;
22 |
23 | import static io.ballerina.scan.RuleKind.VULNERABILITY;
24 | import static io.ballerina.stdlib.jwt.compiler.staticcodeanalyzer.RuleFactory.createRule;
25 |
26 | public enum JwtRule {
27 | AVOID_WEAK_CIPHER_ALGORITHMS(createRule(1, "Avoid using weak cipher algorithms when signing and " +
28 | "verifying JWTs", VULNERABILITY));
29 |
30 | private final Rule rule;
31 |
32 | JwtRule(Rule rule) {
33 | this.rule = rule;
34 | }
35 |
36 | public int getId() {
37 | return this.rule.numericId();
38 | }
39 |
40 | public String getDescription() {
41 | return this.rule.description();
42 | }
43 |
44 | @Override
45 | public String toString() {
46 | return "{\"id\":" + this.getId() + ", \"kind\":\"" + this.rule.kind() + "\"," +
47 | " \"description\" : \"" + this.rule.description() + "\"}";
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/ballerina/tests/resources/key/private.key:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCBXKLp9WJUuJko
3 | SfDn3HM2LWVxiHrP11me6D4X2AqoUiCZ1w976q1LuBlzWNhONYwJvHXewUuRmo0d
4 | 4NRp2ma0qjdMN246XWyozpzPfJdvovfiT+V6HnSbMg82ZppfF3e85Cgrg6mSA7Wf
5 | faaHr62SnexseZ9ioNCuRUrW2Zg208l99IItP4K4iGclQlyjs3S6drH7JJk3rv8B
6 | f76wmmoCEAhknOtGLq543dEUIjFgNdIy/GsSY52fiA4LSjUCv27kGn03nayqoZs3
7 | XHqM0qLdt9SPXbYe7l75j0o6Z9tyGFCKXY/zVwiLfRUqDIOfkN5YS4Ohit52Tj7q
8 | oBmvEzD7AgMBAAECggEAXM/F4u23OummmQ1T1kaIMpqnaalt06jCGAywYBMUsmca
9 | FMYDyfg5lVXkjKl1p8crTeD1AHjWawTjskgYnkmf3ocxXXF3mFBnIUX7o7HURLg7
10 | +RcxoUgwiRiFaZZ7szX3JoLbfzzbcHNQ37kavccBVWwQsFMiU3Tlw+LbKwK6/row
11 | LYsQPx7gT4u7hViat4vQDTYcgyjvvFCiek4ndL6O9K49MxIMU678UXB6ia5iUevy
12 | vgEfcYkKQ5EQ38qS3ZwsubPvj4633jvAJRr/hJD8XINZC74kTXeV3BGH2LlpQOEq
13 | kWkOypwYNjnXtt1JO8+Iu6mEXKUoiIBPfGrJ3vDSQQKBgQDmYPc7kfYan/LHjJRv
14 | iE2CwbC26yVA6+BEPQv9z7jChO9Q6cUbGvM8EEVNpC9nmFogkslzJhz55HP84QZL
15 | u3ptU+D96ncq6zkBqxBfRnZG++D36+XRXIwzz3h+g1Nwrl0y0MFbwlkMm3ZqJdd6
16 | pZz1FZGd6zvQftW8m7jPSKHuswKBgQCPv6czFOZR6bI+qCQdaORpe9JGoAduOD+4
17 | YKl96s0eiAKhkGhFCrMd6GJwWRkpNcfwB+J9sMahORbfvwiYanI56h7Vi30DFPRb
18 | m1m8dLkr6z+8bxMxKJaMXIIjy3UDamgDr7QHInNUih2iGvtB8QqZ0aobsB2XIxZg
19 | qESTMcpYmQKBgHSwSqneraQgvgz7FLhFdtUzHDoacr0mfGqz7R37F99XDAyUy+SF
20 | ywvyRdgkwGodjhEPqH/tnyGn6GP+6nxzknhL0xtppkCT8kT5C4rmmsQrknChCL/5
21 | u34GqUaTaDEb8FLrz/SVRRuQpvLvBey2dADjkuVFH//kLoig64P6iyLnAoGBAIlF
22 | g+2L78YZXVXoS1SqbjUtQUigWXgvzunLpQ/Rwb9+MsUGmgwUg6fz2s1eyGBKM3xM
23 | i0VsIsKjOezBCPxD6oDTyk4yvlbLE+7HE5KcBJikNmFD0RgIonu3e6+jA0MXweyD
24 | RW/qviflHRdInNgDzxPE3KVEMX26zAvRpGrMCWdBAoGAdQ5SvX+mAC3cKqoQ9Zal
25 | lSqWoyjfzP5EaVRG8dtoLxbznQGTTvtHXc65/MznX/L9qkWCS6Eb4HH5M3hFNY46
26 | LNIzGQLznE1odwv7H5B8c0/m3DrKTxbh8bYcrR1BW5/nKZNNW7k1O6OjEozvAajK
27 | JQdp3KBU9S8CmBjGrRpJ2qw=
28 | -----END PRIVATE KEY-----
29 |
--------------------------------------------------------------------------------
/examples/order-management-service/sts/resources/private.key:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCBXKLp9WJUuJko
3 | SfDn3HM2LWVxiHrP11me6D4X2AqoUiCZ1w976q1LuBlzWNhONYwJvHXewUuRmo0d
4 | 4NRp2ma0qjdMN246XWyozpzPfJdvovfiT+V6HnSbMg82ZppfF3e85Cgrg6mSA7Wf
5 | faaHr62SnexseZ9ioNCuRUrW2Zg208l99IItP4K4iGclQlyjs3S6drH7JJk3rv8B
6 | f76wmmoCEAhknOtGLq543dEUIjFgNdIy/GsSY52fiA4LSjUCv27kGn03nayqoZs3
7 | XHqM0qLdt9SPXbYe7l75j0o6Z9tyGFCKXY/zVwiLfRUqDIOfkN5YS4Ohit52Tj7q
8 | oBmvEzD7AgMBAAECggEAXM/F4u23OummmQ1T1kaIMpqnaalt06jCGAywYBMUsmca
9 | FMYDyfg5lVXkjKl1p8crTeD1AHjWawTjskgYnkmf3ocxXXF3mFBnIUX7o7HURLg7
10 | +RcxoUgwiRiFaZZ7szX3JoLbfzzbcHNQ37kavccBVWwQsFMiU3Tlw+LbKwK6/row
11 | LYsQPx7gT4u7hViat4vQDTYcgyjvvFCiek4ndL6O9K49MxIMU678UXB6ia5iUevy
12 | vgEfcYkKQ5EQ38qS3ZwsubPvj4633jvAJRr/hJD8XINZC74kTXeV3BGH2LlpQOEq
13 | kWkOypwYNjnXtt1JO8+Iu6mEXKUoiIBPfGrJ3vDSQQKBgQDmYPc7kfYan/LHjJRv
14 | iE2CwbC26yVA6+BEPQv9z7jChO9Q6cUbGvM8EEVNpC9nmFogkslzJhz55HP84QZL
15 | u3ptU+D96ncq6zkBqxBfRnZG++D36+XRXIwzz3h+g1Nwrl0y0MFbwlkMm3ZqJdd6
16 | pZz1FZGd6zvQftW8m7jPSKHuswKBgQCPv6czFOZR6bI+qCQdaORpe9JGoAduOD+4
17 | YKl96s0eiAKhkGhFCrMd6GJwWRkpNcfwB+J9sMahORbfvwiYanI56h7Vi30DFPRb
18 | m1m8dLkr6z+8bxMxKJaMXIIjy3UDamgDr7QHInNUih2iGvtB8QqZ0aobsB2XIxZg
19 | qESTMcpYmQKBgHSwSqneraQgvgz7FLhFdtUzHDoacr0mfGqz7R37F99XDAyUy+SF
20 | ywvyRdgkwGodjhEPqH/tnyGn6GP+6nxzknhL0xtppkCT8kT5C4rmmsQrknChCL/5
21 | u34GqUaTaDEb8FLrz/SVRRuQpvLvBey2dADjkuVFH//kLoig64P6iyLnAoGBAIlF
22 | g+2L78YZXVXoS1SqbjUtQUigWXgvzunLpQ/Rwb9+MsUGmgwUg6fz2s1eyGBKM3xM
23 | i0VsIsKjOezBCPxD6oDTyk4yvlbLE+7HE5KcBJikNmFD0RgIonu3e6+jA0MXweyD
24 | RW/qviflHRdInNgDzxPE3KVEMX26zAvRpGrMCWdBAoGAdQ5SvX+mAC3cKqoQ9Zal
25 | lSqWoyjfzP5EaVRG8dtoLxbznQGTTvtHXc65/MznX/L9qkWCS6Eb4HH5M3hFNY46
26 | LNIzGQLznE1odwv7H5B8c0/m3DrKTxbh8bYcrR1BW5/nKZNNW7k1O6OjEozvAajK
27 | JQdp3KBU9S8CmBjGrRpJ2qw=
28 | -----END PRIVATE KEY-----
29 |
--------------------------------------------------------------------------------
/load-tests/order_management_service/src/resources/sts/private.key:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCBXKLp9WJUuJko
3 | SfDn3HM2LWVxiHrP11me6D4X2AqoUiCZ1w976q1LuBlzWNhONYwJvHXewUuRmo0d
4 | 4NRp2ma0qjdMN246XWyozpzPfJdvovfiT+V6HnSbMg82ZppfF3e85Cgrg6mSA7Wf
5 | faaHr62SnexseZ9ioNCuRUrW2Zg208l99IItP4K4iGclQlyjs3S6drH7JJk3rv8B
6 | f76wmmoCEAhknOtGLq543dEUIjFgNdIy/GsSY52fiA4LSjUCv27kGn03nayqoZs3
7 | XHqM0qLdt9SPXbYe7l75j0o6Z9tyGFCKXY/zVwiLfRUqDIOfkN5YS4Ohit52Tj7q
8 | oBmvEzD7AgMBAAECggEAXM/F4u23OummmQ1T1kaIMpqnaalt06jCGAywYBMUsmca
9 | FMYDyfg5lVXkjKl1p8crTeD1AHjWawTjskgYnkmf3ocxXXF3mFBnIUX7o7HURLg7
10 | +RcxoUgwiRiFaZZ7szX3JoLbfzzbcHNQ37kavccBVWwQsFMiU3Tlw+LbKwK6/row
11 | LYsQPx7gT4u7hViat4vQDTYcgyjvvFCiek4ndL6O9K49MxIMU678UXB6ia5iUevy
12 | vgEfcYkKQ5EQ38qS3ZwsubPvj4633jvAJRr/hJD8XINZC74kTXeV3BGH2LlpQOEq
13 | kWkOypwYNjnXtt1JO8+Iu6mEXKUoiIBPfGrJ3vDSQQKBgQDmYPc7kfYan/LHjJRv
14 | iE2CwbC26yVA6+BEPQv9z7jChO9Q6cUbGvM8EEVNpC9nmFogkslzJhz55HP84QZL
15 | u3ptU+D96ncq6zkBqxBfRnZG++D36+XRXIwzz3h+g1Nwrl0y0MFbwlkMm3ZqJdd6
16 | pZz1FZGd6zvQftW8m7jPSKHuswKBgQCPv6czFOZR6bI+qCQdaORpe9JGoAduOD+4
17 | YKl96s0eiAKhkGhFCrMd6GJwWRkpNcfwB+J9sMahORbfvwiYanI56h7Vi30DFPRb
18 | m1m8dLkr6z+8bxMxKJaMXIIjy3UDamgDr7QHInNUih2iGvtB8QqZ0aobsB2XIxZg
19 | qESTMcpYmQKBgHSwSqneraQgvgz7FLhFdtUzHDoacr0mfGqz7R37F99XDAyUy+SF
20 | ywvyRdgkwGodjhEPqH/tnyGn6GP+6nxzknhL0xtppkCT8kT5C4rmmsQrknChCL/5
21 | u34GqUaTaDEb8FLrz/SVRRuQpvLvBey2dADjkuVFH//kLoig64P6iyLnAoGBAIlF
22 | g+2L78YZXVXoS1SqbjUtQUigWXgvzunLpQ/Rwb9+MsUGmgwUg6fz2s1eyGBKM3xM
23 | i0VsIsKjOezBCPxD6oDTyk4yvlbLE+7HE5KcBJikNmFD0RgIonu3e6+jA0MXweyD
24 | RW/qviflHRdInNgDzxPE3KVEMX26zAvRpGrMCWdBAoGAdQ5SvX+mAC3cKqoQ9Zal
25 | lSqWoyjfzP5EaVRG8dtoLxbznQGTTvtHXc65/MznX/L9qkWCS6Eb4HH5M3hFNY46
26 | LNIzGQLznE1odwv7H5B8c0/m3DrKTxbh8bYcrR1BW5/nKZNNW7k1O6OjEozvAajK
27 | JQdp3KBU9S8CmBjGrRpJ2qw=
28 | -----END PRIVATE KEY-----
29 |
--------------------------------------------------------------------------------
/examples/order-management-service/inventory_service/resources/private.key:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCBXKLp9WJUuJko
3 | SfDn3HM2LWVxiHrP11me6D4X2AqoUiCZ1w976q1LuBlzWNhONYwJvHXewUuRmo0d
4 | 4NRp2ma0qjdMN246XWyozpzPfJdvovfiT+V6HnSbMg82ZppfF3e85Cgrg6mSA7Wf
5 | faaHr62SnexseZ9ioNCuRUrW2Zg208l99IItP4K4iGclQlyjs3S6drH7JJk3rv8B
6 | f76wmmoCEAhknOtGLq543dEUIjFgNdIy/GsSY52fiA4LSjUCv27kGn03nayqoZs3
7 | XHqM0qLdt9SPXbYe7l75j0o6Z9tyGFCKXY/zVwiLfRUqDIOfkN5YS4Ohit52Tj7q
8 | oBmvEzD7AgMBAAECggEAXM/F4u23OummmQ1T1kaIMpqnaalt06jCGAywYBMUsmca
9 | FMYDyfg5lVXkjKl1p8crTeD1AHjWawTjskgYnkmf3ocxXXF3mFBnIUX7o7HURLg7
10 | +RcxoUgwiRiFaZZ7szX3JoLbfzzbcHNQ37kavccBVWwQsFMiU3Tlw+LbKwK6/row
11 | LYsQPx7gT4u7hViat4vQDTYcgyjvvFCiek4ndL6O9K49MxIMU678UXB6ia5iUevy
12 | vgEfcYkKQ5EQ38qS3ZwsubPvj4633jvAJRr/hJD8XINZC74kTXeV3BGH2LlpQOEq
13 | kWkOypwYNjnXtt1JO8+Iu6mEXKUoiIBPfGrJ3vDSQQKBgQDmYPc7kfYan/LHjJRv
14 | iE2CwbC26yVA6+BEPQv9z7jChO9Q6cUbGvM8EEVNpC9nmFogkslzJhz55HP84QZL
15 | u3ptU+D96ncq6zkBqxBfRnZG++D36+XRXIwzz3h+g1Nwrl0y0MFbwlkMm3ZqJdd6
16 | pZz1FZGd6zvQftW8m7jPSKHuswKBgQCPv6czFOZR6bI+qCQdaORpe9JGoAduOD+4
17 | YKl96s0eiAKhkGhFCrMd6GJwWRkpNcfwB+J9sMahORbfvwiYanI56h7Vi30DFPRb
18 | m1m8dLkr6z+8bxMxKJaMXIIjy3UDamgDr7QHInNUih2iGvtB8QqZ0aobsB2XIxZg
19 | qESTMcpYmQKBgHSwSqneraQgvgz7FLhFdtUzHDoacr0mfGqz7R37F99XDAyUy+SF
20 | ywvyRdgkwGodjhEPqH/tnyGn6GP+6nxzknhL0xtppkCT8kT5C4rmmsQrknChCL/5
21 | u34GqUaTaDEb8FLrz/SVRRuQpvLvBey2dADjkuVFH//kLoig64P6iyLnAoGBAIlF
22 | g+2L78YZXVXoS1SqbjUtQUigWXgvzunLpQ/Rwb9+MsUGmgwUg6fz2s1eyGBKM3xM
23 | i0VsIsKjOezBCPxD6oDTyk4yvlbLE+7HE5KcBJikNmFD0RgIonu3e6+jA0MXweyD
24 | RW/qviflHRdInNgDzxPE3KVEMX26zAvRpGrMCWdBAoGAdQ5SvX+mAC3cKqoQ9Zal
25 | lSqWoyjfzP5EaVRG8dtoLxbznQGTTvtHXc65/MznX/L9qkWCS6Eb4HH5M3hFNY46
26 | LNIzGQLznE1odwv7H5B8c0/m3DrKTxbh8bYcrR1BW5/nKZNNW7k1O6OjEozvAajK
27 | JQdp3KBU9S8CmBjGrRpJ2qw=
28 | -----END PRIVATE KEY-----
29 |
--------------------------------------------------------------------------------
/examples/order-management-service/order_service/resources/private.key:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCBXKLp9WJUuJko
3 | SfDn3HM2LWVxiHrP11me6D4X2AqoUiCZ1w976q1LuBlzWNhONYwJvHXewUuRmo0d
4 | 4NRp2ma0qjdMN246XWyozpzPfJdvovfiT+V6HnSbMg82ZppfF3e85Cgrg6mSA7Wf
5 | faaHr62SnexseZ9ioNCuRUrW2Zg208l99IItP4K4iGclQlyjs3S6drH7JJk3rv8B
6 | f76wmmoCEAhknOtGLq543dEUIjFgNdIy/GsSY52fiA4LSjUCv27kGn03nayqoZs3
7 | XHqM0qLdt9SPXbYe7l75j0o6Z9tyGFCKXY/zVwiLfRUqDIOfkN5YS4Ohit52Tj7q
8 | oBmvEzD7AgMBAAECggEAXM/F4u23OummmQ1T1kaIMpqnaalt06jCGAywYBMUsmca
9 | FMYDyfg5lVXkjKl1p8crTeD1AHjWawTjskgYnkmf3ocxXXF3mFBnIUX7o7HURLg7
10 | +RcxoUgwiRiFaZZ7szX3JoLbfzzbcHNQ37kavccBVWwQsFMiU3Tlw+LbKwK6/row
11 | LYsQPx7gT4u7hViat4vQDTYcgyjvvFCiek4ndL6O9K49MxIMU678UXB6ia5iUevy
12 | vgEfcYkKQ5EQ38qS3ZwsubPvj4633jvAJRr/hJD8XINZC74kTXeV3BGH2LlpQOEq
13 | kWkOypwYNjnXtt1JO8+Iu6mEXKUoiIBPfGrJ3vDSQQKBgQDmYPc7kfYan/LHjJRv
14 | iE2CwbC26yVA6+BEPQv9z7jChO9Q6cUbGvM8EEVNpC9nmFogkslzJhz55HP84QZL
15 | u3ptU+D96ncq6zkBqxBfRnZG++D36+XRXIwzz3h+g1Nwrl0y0MFbwlkMm3ZqJdd6
16 | pZz1FZGd6zvQftW8m7jPSKHuswKBgQCPv6czFOZR6bI+qCQdaORpe9JGoAduOD+4
17 | YKl96s0eiAKhkGhFCrMd6GJwWRkpNcfwB+J9sMahORbfvwiYanI56h7Vi30DFPRb
18 | m1m8dLkr6z+8bxMxKJaMXIIjy3UDamgDr7QHInNUih2iGvtB8QqZ0aobsB2XIxZg
19 | qESTMcpYmQKBgHSwSqneraQgvgz7FLhFdtUzHDoacr0mfGqz7R37F99XDAyUy+SF
20 | ywvyRdgkwGodjhEPqH/tnyGn6GP+6nxzknhL0xtppkCT8kT5C4rmmsQrknChCL/5
21 | u34GqUaTaDEb8FLrz/SVRRuQpvLvBey2dADjkuVFH//kLoig64P6iyLnAoGBAIlF
22 | g+2L78YZXVXoS1SqbjUtQUigWXgvzunLpQ/Rwb9+MsUGmgwUg6fz2s1eyGBKM3xM
23 | i0VsIsKjOezBCPxD6oDTyk4yvlbLE+7HE5KcBJikNmFD0RgIonu3e6+jA0MXweyD
24 | RW/qviflHRdInNgDzxPE3KVEMX26zAvRpGrMCWdBAoGAdQ5SvX+mAC3cKqoQ9Zal
25 | lSqWoyjfzP5EaVRG8dtoLxbznQGTTvtHXc65/MznX/L9qkWCS6Eb4HH5M3hFNY46
26 | LNIzGQLznE1odwv7H5B8c0/m3DrKTxbh8bYcrR1BW5/nKZNNW7k1O6OjEozvAajK
27 | JQdp3KBU9S8CmBjGrRpJ2qw=
28 | -----END PRIVATE KEY-----
29 |
--------------------------------------------------------------------------------
/load-tests/order_management_service/src/resources/order_service/private.key:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCBXKLp9WJUuJko
3 | SfDn3HM2LWVxiHrP11me6D4X2AqoUiCZ1w976q1LuBlzWNhONYwJvHXewUuRmo0d
4 | 4NRp2ma0qjdMN246XWyozpzPfJdvovfiT+V6HnSbMg82ZppfF3e85Cgrg6mSA7Wf
5 | faaHr62SnexseZ9ioNCuRUrW2Zg208l99IItP4K4iGclQlyjs3S6drH7JJk3rv8B
6 | f76wmmoCEAhknOtGLq543dEUIjFgNdIy/GsSY52fiA4LSjUCv27kGn03nayqoZs3
7 | XHqM0qLdt9SPXbYe7l75j0o6Z9tyGFCKXY/zVwiLfRUqDIOfkN5YS4Ohit52Tj7q
8 | oBmvEzD7AgMBAAECggEAXM/F4u23OummmQ1T1kaIMpqnaalt06jCGAywYBMUsmca
9 | FMYDyfg5lVXkjKl1p8crTeD1AHjWawTjskgYnkmf3ocxXXF3mFBnIUX7o7HURLg7
10 | +RcxoUgwiRiFaZZ7szX3JoLbfzzbcHNQ37kavccBVWwQsFMiU3Tlw+LbKwK6/row
11 | LYsQPx7gT4u7hViat4vQDTYcgyjvvFCiek4ndL6O9K49MxIMU678UXB6ia5iUevy
12 | vgEfcYkKQ5EQ38qS3ZwsubPvj4633jvAJRr/hJD8XINZC74kTXeV3BGH2LlpQOEq
13 | kWkOypwYNjnXtt1JO8+Iu6mEXKUoiIBPfGrJ3vDSQQKBgQDmYPc7kfYan/LHjJRv
14 | iE2CwbC26yVA6+BEPQv9z7jChO9Q6cUbGvM8EEVNpC9nmFogkslzJhz55HP84QZL
15 | u3ptU+D96ncq6zkBqxBfRnZG++D36+XRXIwzz3h+g1Nwrl0y0MFbwlkMm3ZqJdd6
16 | pZz1FZGd6zvQftW8m7jPSKHuswKBgQCPv6czFOZR6bI+qCQdaORpe9JGoAduOD+4
17 | YKl96s0eiAKhkGhFCrMd6GJwWRkpNcfwB+J9sMahORbfvwiYanI56h7Vi30DFPRb
18 | m1m8dLkr6z+8bxMxKJaMXIIjy3UDamgDr7QHInNUih2iGvtB8QqZ0aobsB2XIxZg
19 | qESTMcpYmQKBgHSwSqneraQgvgz7FLhFdtUzHDoacr0mfGqz7R37F99XDAyUy+SF
20 | ywvyRdgkwGodjhEPqH/tnyGn6GP+6nxzknhL0xtppkCT8kT5C4rmmsQrknChCL/5
21 | u34GqUaTaDEb8FLrz/SVRRuQpvLvBey2dADjkuVFH//kLoig64P6iyLnAoGBAIlF
22 | g+2L78YZXVXoS1SqbjUtQUigWXgvzunLpQ/Rwb9+MsUGmgwUg6fz2s1eyGBKM3xM
23 | i0VsIsKjOezBCPxD6oDTyk4yvlbLE+7HE5KcBJikNmFD0RgIonu3e6+jA0MXweyD
24 | RW/qviflHRdInNgDzxPE3KVEMX26zAvRpGrMCWdBAoGAdQ5SvX+mAC3cKqoQ9Zal
25 | lSqWoyjfzP5EaVRG8dtoLxbznQGTTvtHXc65/MznX/L9qkWCS6Eb4HH5M3hFNY46
26 | LNIzGQLznE1odwv7H5B8c0/m3DrKTxbh8bYcrR1BW5/nKZNNW7k1O6OjEozvAajK
27 | JQdp3KBU9S8CmBjGrRpJ2qw=
28 | -----END PRIVATE KEY-----
29 |
--------------------------------------------------------------------------------
/ballerina/tests/resources/key/encryptedPrivate.key:
--------------------------------------------------------------------------------
1 | -----BEGIN ENCRYPTED PRIVATE KEY-----
2 | MIIE6jAcBgoqhkiG9w0BDAEEMA4ECJ1AVEOFT+s1AgIFDASCBMiHG70PvakbuVha
3 | 9JBcXWzje1B30LItVdpiETbu5LNG3v0IIX7DmRQCBJxXkkCeZ3Bcw/A1cjkGIR0j
4 | 6P1AyUAlZBU9+GcCF2BcpyaMOxNVQuHUZA9//fnlfO6KMTdIg9b/MutH++bLSoh9
5 | JkHivtgEQVEAu79NpTdKh9XklIWUBe5gU4OteBL0/feKgB6NFeYm7vNb8b486jSB
6 | oXWC7l8Y5VoU4grhDT9dL1PQqLQvIRWTnB1BhUE9OquWrRRaGE7WeWABzzFhHB4X
7 | DdHABqsNE9qeEGHrUBKfjfg6+8GIEjjJcpJt9wGBi4yHbUaao7xueu0aA9nVVo75
8 | 6PJOwcJqoPhwkDFpAYADLJTVxh8EqbaihSe3HVqjsF3au5nu338VbJu8VZ2rAgTv
9 | V2IxsV/BWrv8RIbt/EINz82uU0umbhpvUakMjZGD01NCvx6mshfKA3zIEac7apmc
10 | 6wwoqh42sEHk3i7H/xQhuS32ACzRDwXzXYf2f8CZVrSk7Ajc4w4mwY5YylCmn+P5
11 | YK6fRCaJAN2J4CGvIut3LvjGX8pNuu9msFMrFjbITL/xeUzIrJoE1C9O2V1dQ5LU
12 | O4wVFGKHkFpBBzxxDQwRbYn66EbL4/dCwtIkj7kncz7Y+qYBi+Voe81RSL1mBtR/
13 | nOQPIHNOLSUvIPA2aj4ufcdSrbXapMfrTOiO+EUuBOGE6FncaGm3hfKnPa1C4fuZ
14 | yokvpEMNOUs5eJjSC0tcP+zibTkiMHy2vhvrI3xme6oIFG7Nvxi2MxcWolUNmXlk
15 | UVGyJJurL9QhKfjGSIuEZgJd7/PrDK0gzEQBMS/10BUPRe1pE+05GEOvJBbhw1Bt
16 | 6b3LjbVtNnR/2/G3I9LlwRLac4IHlU/JMy58E3Uxim0/rJJ7uGGbXsxdwFS4968I
17 | /ekA1PcZgvNet60rMYxSXz6QPwYnvM94gFD6I5PgUhJJPeQZiw9kFLBqKsUjBrjY
18 | jFAcTVW6sWEo1CMsUC94gwvHvpOLtPHjik/iPAfHXeGQ9baTaArMAJiQO+0h9O3Y
19 | 0rXM8gEz4zAID3N4neVjjMda7C/2avAfJRoBxYAFMcuMNTta4mMmXOCs+M6x45GI
20 | w/KPAZbsRTcRWLjU5QguqP6eAxSghHITruW0HEqscT20K3cRWXXDEOr8ZqId90xY
21 | PQo5ZEvaJLGgxN4Q7CUPJJ1mKHruTmMm+UOxIuXRR2eaqsJDnLovmu4jGOSLVYV4
22 | FFJ7PxD+tx9b8WS8tckS/Pjm2PcUAJz3I6/DFc3iKwoeCXBIG/djwWfabRcoGb0U
23 | Sq8tiqvCjT/LuubpQgKhkEnxWCBRR+Qns4quJJ2Kead/g8E19cUxolGPTW9jr2GF
24 | 1XWuGytK0PqUOIMsuJkhWN3dErFmftcfmfhqFFulOvE7eWr+ZToyFESmNK+MNnAL
25 | mmZFOt7zTNwooQkzpVohLtKPwe3k71dhhsK3gQBoscKQFnMQSmKLM7c4A6HPcq20
26 | XFtRM30O5cSO2jLZ+sAcJS81uIrcPWWf8yY5lMZ1irHFri6jnwcv7Sbe3rqZJFer
27 | 9ckVz4rq399UHOyujNT2gjIaFnEwmHfM0yaZ0dYG2JU/jXdbqsTLKsHSOZsrkkL5
28 | 9BaHO8wfzVx/CnQfP6M=
29 | -----END ENCRYPTED PRIVATE KEY-----
30 |
--------------------------------------------------------------------------------
/examples/order-management-service/inventory_service/inventory_service.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2021, 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 | import ballerina/http;
18 | import inventory_service.inventory as inv;
19 | import inventory_service.representations as rep;
20 |
21 | listener http:Listener inventoryEP = new (9091,
22 | secureSocket = {
23 | key: {
24 | certFile: "./resources/public.crt",
25 | keyFile: "./resources/private.key"
26 | },
27 | mutualSsl: {
28 | verifyClient: http:REQUIRE,
29 | cert: "./resources/public.crt"
30 | }
31 | }
32 | );
33 |
34 | service /inventory on inventoryEP {
35 | resource function put decrease(@http:Payload rep:OrderItem[] orderItems) returns rep:InventoryUpdated {
36 | foreach rep:OrderItem orderItem in orderItems {
37 | inv:decreaseQty(orderItem.category, orderItem.code, orderItem.qty);
38 | }
39 | return {};
40 | }
41 |
42 | resource function put increase(@http:Payload rep:OrderItem[] orderItems) returns rep:InventoryUpdated {
43 | foreach rep:OrderItem orderItem in orderItems {
44 | inv:increaseQty(orderItem.category, orderItem.code, orderItem.qty);
45 | }
46 | return {};
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * This file was generated by the Gradle 'init' task.
3 | *
4 | * The settings file is used to specify which projects to include in your build.
5 | *
6 | * Detailed information about configuring a multi-project build in Gradle can be found
7 | * in the user manual at https://docs.gradle.org/6.3/userguide/multi_project_builds.html
8 | */
9 |
10 | pluginManagement {
11 | plugins {
12 | id "com.github.spotbugs" version "${spotbugsPluginVersion}"
13 | id "com.github.johnrengelman.shadow" version "${shadowJarPluginVersion}"
14 | id "de.undercouch.download" version "${downloadPluginVersion}"
15 | id "net.researchgate.release" version "${releasePluginVersion}"
16 | id "io.ballerina.plugin" version "${ballerinaGradlePluginVersion}"
17 | }
18 |
19 | repositories {
20 | gradlePluginPortal()
21 | maven {
22 | url = 'https://maven.pkg.github.com/ballerina-platform/*'
23 | credentials {
24 | username System.getenv("packageUser")
25 | password System.getenv("packagePAT")
26 | }
27 | }
28 | }
29 | }
30 |
31 | plugins {
32 | id "com.gradle.enterprise" version "3.13.2"
33 | }
34 |
35 | rootProject.name = 'jwt'
36 |
37 | include ':checkstyle'
38 | include ':jwt-native'
39 | include ':jwt-ballerina'
40 | include ':jwt-compiler-plugin'
41 | include ':jwt-compiler-plugin-tests'
42 |
43 | project(':checkstyle').projectDir = file("build-config${File.separator}checkstyle")
44 | project(':jwt-native').projectDir = file('native')
45 | project(':jwt-ballerina').projectDir = file('ballerina')
46 | project(':jwt-compiler-plugin').projectDir = file('compiler-plugin')
47 | project(':jwt-compiler-plugin-tests').projectDir = file('compiler-plugin-tests')
48 |
49 | gradleEnterprise {
50 | buildScan {
51 | termsOfServiceUrl = 'https://gradle.com/terms-of-service'
52 | termsOfServiceAgree = 'yes'
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/load-tests/order_management_service/src/order_service.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2021, 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 | import ballerina/cache;
18 | import ballerina/http;
19 |
20 | final http:JwtValidatorConfig config = {
21 | issuer: "wso2",
22 | audience: "ballerina",
23 | signatureConfig: {
24 | jwksConfig: {
25 | url: "https://localhost:9445/oauth2/jwks",
26 | clientConfig: {
27 | secureSocket: {
28 | cert: "./resources/order_service/public.crt"
29 | }
30 | },
31 | cacheConfig: {
32 | capacity: 10,
33 | evictionFactor: 0.25,
34 | evictionPolicy: cache:LRU,
35 | defaultMaxAge: -1
36 | }
37 | }
38 | },
39 | cacheConfig: {
40 | capacity: 10,
41 | evictionFactor: 0.25,
42 | evictionPolicy: cache:LRU,
43 | defaultMaxAge: -1
44 | }
45 | };
46 |
47 | listener http:Listener orderEP = new (9090,
48 | secureSocket = {
49 | key: {
50 | certFile: "./resources/order_service/public.crt",
51 | keyFile: "./resources/order_service/private.key"
52 | }
53 | }
54 | );
55 |
56 | isolated service /'order on orderEP {
57 |
58 | @http:ResourceConfig {
59 | auth: [
60 | {
61 | jwtValidatorConfig: config,
62 | scopes: "add_order"
63 | }
64 | ]
65 | }
66 | isolated resource function post .(@http:Payload json payload) returns json {
67 | return payload;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/native/src/main/java/io/ballerina/stdlib/jwt/JwtUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. 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 | package io.ballerina.stdlib.jwt;
20 |
21 | import io.ballerina.runtime.api.creators.ErrorCreator;
22 | import io.ballerina.runtime.api.creators.ValueCreator;
23 | import io.ballerina.runtime.api.utils.StringUtils;
24 | import io.ballerina.runtime.api.values.BArray;
25 | import io.ballerina.runtime.api.values.BError;
26 | import io.ballerina.runtime.api.values.BString;
27 |
28 | import java.nio.charset.StandardCharsets;
29 | import java.util.Base64;
30 |
31 | /**
32 | * JWT related utility functions.
33 | *
34 | * @since 2.0.0
35 | */
36 | public class JwtUtils {
37 |
38 | private JwtUtils() {}
39 |
40 | public static BString encodeBase64Url(BArray input) {
41 | byte[] encodedValue = Base64.getUrlEncoder().withoutPadding().encode(input.getBytes());
42 | return StringUtils.fromString(new String(encodedValue, StandardCharsets.ISO_8859_1));
43 | }
44 |
45 | public static Object decodeBase64Url(BString input) {
46 | try {
47 | byte[] output = Base64.getUrlDecoder().decode(input.getValue());
48 | return ValueCreator.createArrayValue(output);
49 | } catch (IllegalArgumentException e) {
50 | return createError("Input is not a valid Base64 URL encoded value. " + e.getMessage());
51 | }
52 | }
53 |
54 | public static BError createError(String errMsg) {
55 | return ErrorCreator.createDistinctError(JwtConstants.JWT_ERROR_TYPE, ModuleUtils.getModule(),
56 | StringUtils.fromString(errMsg));
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/ballerina/client_self_signed_jwt_auth_provider.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2019 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 | # Represents the client JWT Auth provider, which is used to authenticate with an external endpoint by issuing a
18 | # self-signed JWT against the provided JWT issuer configurations.
19 | # ```ballerina
20 | # jwt:ClientSelfSignedJwtAuthProvider provider = new({
21 | # issuer: "wso2",
22 | # audience: "ballerina",
23 | # keyStoreConfig: {
24 | # keyAlias: "ballerina",
25 | # keyPassword: "ballerina",
26 | # keyStore: {
27 | # path: "/path/to/keystore.p12",
28 | # password: "ballerina"
29 | # }
30 | # }
31 | # });
32 | # ```
33 | public isolated class ClientSelfSignedJwtAuthProvider {
34 |
35 | private final IssuerConfig & readonly issuerConfig;
36 |
37 | # Provides authentication based on the provided JWT configurations.
38 | #
39 | # + issuerConfig - JWT issuer configurations
40 | public isolated function init(IssuerConfig issuerConfig) {
41 | self.issuerConfig = issuerConfig.cloneReadOnly();
42 | }
43 |
44 | # Issues a self-signed JWT for authentication.
45 | # ```ballerina
46 | # string token = check provider.generateToken();
47 | # ```
48 | #
49 | # + return - Generated token or else a `jwt:Error` if an error occurred
50 | public isolated function generateToken() returns string|Error {
51 | string|Error result = issue(self.issuerConfig);
52 | if result is string {
53 | return result;
54 | } else {
55 | return prepareError("Failed to generate a self-signed JWT.", result);
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/ballerina/README.md:
--------------------------------------------------------------------------------
1 | ## Overview
2 |
3 | This module provides a framework for authentication/authorization with JWTs and generation/validation of JWTs as specified in the [RFC 7519](https://datatracker.ietf.org/doc/html/rfc7519), [RFC 7515](https://datatracker.ietf.org/doc/html/rfc7515), and [RFC 7517](https://datatracker.ietf.org/doc/html/rfc7517).
4 |
5 | JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is used as the payload of a JSON Web Signature (JWS) structure or as the plaintext of a JSON Web Encryption (JWE) structure enabling the claims to be signed digitally or protecting the integrity with a Message Authentication Code(MAC) and/or encrypted.
6 |
7 | The Ballerina `jwt` module facilitates auth providers that are to be used by the clients and listeners of different protocol connectors. Also, it provides the APIs for issuing a self-signed JWT and validating a JWT.
8 |
9 | ### Listener JWT Auth provider
10 |
11 | Represents the listener JWT Auth provider, which is used to authenticate the provided credentials (JWT) against the provided JWT validator configurations.
12 |
13 | ### Client JWT Auth provider
14 |
15 | Represents the client JWT Auth provider, which is used to authenticate with an external endpoint by issuing a self-signed JWT against the provided JWT issuer configurations.
16 |
17 | ### JWT issuer
18 |
19 | A self-signed JWT can be issued with the provided configurations using this API as follows:
20 |
21 | ```ballerina
22 | jwt:IssuerConfig issuerConfig = {
23 | username: "ballerina",
24 | issuer: "wso2",
25 | audience: "vEwzbcasJVQm1jVYHUHCjhxZ4tYa",
26 | expTime: 3600,
27 | signatureConfig: {
28 | config: {
29 | keyFile: "/path/to/private.key"
30 | }
31 | }
32 | };
33 |
34 | string jwt = check jwt:issue(issuerConfig);
35 | ```
36 |
37 | ### JWT validator
38 |
39 | A JWT can be validated with the provided configurations using the API as follows:
40 |
41 | ```ballerina
42 | string jwt = "eyJ0eXAiOiJKV1QiLA0KI[...omitted for brevity...]mB92K27uhbwW1gFWFOEjXk";
43 |
44 | jwt:ValidatorConfig validatorConfig = {
45 | issuer: "wso2",
46 | audience: "vEwzbcasJVQm1jVYHUHCjhxZ4tYa",
47 | clockSkew: 60,
48 | signatureConfig: {
49 | certFile: "/path/to/public.crt"
50 | }
51 | };
52 |
53 | jwt:Payload result = check jwt:validate(jwt, validatorConfig);
54 | ```
55 |
--------------------------------------------------------------------------------
/native/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except 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, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | plugins {
19 | id 'java'
20 | id 'checkstyle'
21 | id 'com.github.spotbugs'
22 | }
23 |
24 | description = 'Ballerina - JWT Java Utils'
25 |
26 | dependencies {
27 | checkstyle project(':checkstyle')
28 | checkstyle "com.puppycrawl.tools:checkstyle:${checkstylePluginVersion}"
29 |
30 | implementation group: 'org.ballerinalang', name: 'ballerina-runtime', version: "${ballerinaLangVersion}"
31 | implementation group: 'io.ballerina.stdlib', name: 'crypto-native', version: "${stdlibCryptoVersion}"
32 | }
33 |
34 | checkstyle {
35 | toolVersion '7.8.2'
36 | configFile rootProject.file("build-config/checkstyle/build/checkstyle.xml")
37 | configProperties = ["suppressionFile" : file("${rootDir}/build-config/checkstyle/build/suppressions.xml")]
38 | }
39 |
40 | checkstyleMain.dependsOn(":checkstyle:downloadCheckstyleRuleFiles")
41 |
42 | spotbugsMain {
43 | def classLoader = plugins["com.github.spotbugs"].class.classLoader
44 | def SpotBugsConfidence = classLoader.findLoadedClass("com.github.spotbugs.snom.Confidence")
45 | def SpotBugsEffort = classLoader.findLoadedClass("com.github.spotbugs.snom.Effort")
46 | effort = SpotBugsEffort.MAX
47 | reportLevel = SpotBugsConfidence.LOW
48 | reportsDir = file("$project.buildDir/reports/spotbugs")
49 | reports {
50 | html.enabled true
51 | text.enabled = true
52 | }
53 | def excludeFile = file("${rootDir}/spotbugs-exclude.xml")
54 | if (excludeFile.exists()) {
55 | excludeFilter = excludeFile
56 | }
57 | }
58 |
59 | def excludePattern = '**/module-info.java'
60 | tasks.withType(Checkstyle) {
61 | exclude excludePattern
62 | }
63 |
64 | compileJava {
65 | doFirst {
66 | options.compilerArgs = [
67 | '--module-path', classpath.asPath,
68 | ]
69 | classpath = files()
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/examples/order-management-service/sts/sts.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2021, 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 | import ballerina/http;
18 |
19 | listener http:Listener sts = new(9445,
20 | secureSocket = {
21 | key: {
22 | certFile: "./resources/public.crt",
23 | keyFile: "./resources/private.key"
24 | }
25 | }
26 | );
27 |
28 | service /oauth2 on sts {
29 |
30 | // This JWKs endpoint respond with a JSON object that represents a set of JWKs.
31 | // https://tools.ietf.org/html/rfc7517#section-5
32 | resource function get jwks() returns json {
33 | return {
34 | "keys": [{
35 | "kty": "EC",
36 | "crv": "P-256",
37 | "x": "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
38 | "y": "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
39 | "use": "enc",
40 | "kid": "1"
41 | },
42 | {
43 | "kty": "RSA",
44 | "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
45 | "e": "AQAB",
46 | "alg": "RS256",
47 | "kid": "2011-04-29"
48 | },
49 | {
50 | "kty": "RSA",
51 | "e": "AQAB",
52 | "use": "sig",
53 | "kid": "NTAxZmMxNDMyZDg3MTU1ZGM0MzEzODJhZWI4NDNlZDU1OGFkNjFiMQ",
54 | "alg": "RS256",
55 | "n": "AIFcoun1YlS4mShJ8OfcczYtZXGIes_XWZ7oPhfYCqhSIJnXD3vqrUu4GXNY2E41jAm8dd7BS5GajR3g1GnaZrSqN0w3bjpdbKjOnM98l2-i9-JP5XoedJsyDzZmml8Xd7zkKCuDqZIDtZ99poevrZKd7Gx5n2Kg0K5FStbZmDbTyX30gi0_griIZyVCXKOzdLp2sfskmTeu_wF_vrCaagIQCGSc60Yurnjd0RQiMWA10jL8axJjnZ-IDgtKNQK_buQafTedrKqhmzdceozSot231I9dth7uXvmPSjpn23IYUIpdj_NXCIt9FSoMg5-Q3lhLg6GK3nZOPuqgGa8TMPs="
56 | }]
57 | };
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/load-tests/order_management_service/src/sts.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2021, 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 | import ballerina/http;
18 |
19 | listener http:Listener sts = new(9445,
20 | secureSocket = {
21 | key: {
22 | certFile: "./resources/sts/public.crt",
23 | keyFile: "./resources/sts/private.key"
24 | }
25 | }
26 | );
27 |
28 | isolated service /oauth2 on sts {
29 |
30 | // This JWKs endpoint respond with a JSON object that represents a set of JWKs.
31 | // https://tools.ietf.org/html/rfc7517#section-5
32 | isolated resource function get jwks() returns json {
33 | return {
34 | "keys": [{
35 | "kty": "EC",
36 | "crv": "P-256",
37 | "x": "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
38 | "y": "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
39 | "use": "enc",
40 | "kid": "1"
41 | },
42 | {
43 | "kty": "RSA",
44 | "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
45 | "e": "AQAB",
46 | "alg": "RS256",
47 | "kid": "2011-04-29"
48 | },
49 | {
50 | "kty": "RSA",
51 | "e": "AQAB",
52 | "use": "sig",
53 | "kid": "NTAxZmMxNDMyZDg3MTU1ZGM0MzEzODJhZWI4NDNlZDU1OGFkNjFiMQ",
54 | "alg": "RS256",
55 | "n": "AIFcoun1YlS4mShJ8OfcczYtZXGIes_XWZ7oPhfYCqhSIJnXD3vqrUu4GXNY2E41jAm8dd7BS5GajR3g1GnaZrSqN0w3bjpdbKjOnM98l2-i9-JP5XoedJsyDzZmml8Xd7zkKCuDqZIDtZ99poevrZKd7Gx5n2Kg0K5FStbZmDbTyX30gi0_griIZyVCXKOzdLp2sfskmTeu_wF_vrCaagIQCGSc60Yurnjd0RQiMWA10jL8axJjnZ-IDgtKNQK_buQafTedrKqhmzdceozSot231I9dth7uXvmPSjpn23IYUIpdj_NXCIt9FSoMg5-Q3lhLg6GK3nZOPuqgGa8TMPs="
56 | }]
57 | };
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/native/src/main/java/io/ballerina/stdlib/jwt/JwtConstants.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. 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 | package io.ballerina.stdlib.jwt;
20 |
21 | import io.ballerina.runtime.api.utils.StringUtils;
22 | import io.ballerina.runtime.api.values.BString;
23 |
24 | /**
25 | * Constants related to Ballerina JWT stdlib.
26 | */
27 | public class JwtConstants {
28 |
29 | private JwtConstants() {}
30 |
31 | public static final String JWT_ERROR_TYPE = "Error";
32 |
33 | public static final String SINGLE_SLASH = "/";
34 | public static final String DOUBLE_SLASH = "//";
35 | public static final String SCHEME_SEPARATOR = "://";
36 | public static final String HTTP_SCHEME = "http";
37 | public static final String HTTPS_SCHEME = "https";
38 |
39 | public static final BString HTTP_VERSION = StringUtils.fromString("httpVersion");
40 | public static final BString SECURE_SOCKET = StringUtils.fromString("secureSocket");
41 | public static final BString DISABLE = StringUtils.fromString("disable");
42 | public static final BString CERT = StringUtils.fromString("cert");
43 | public static final BString KEY = StringUtils.fromString("key");
44 | public static final BString CERT_FILE = StringUtils.fromString("certFile");
45 | public static final BString KEY_FILE = StringUtils.fromString("keyFile");
46 | public static final BString KEY_PASSWORD = StringUtils.fromString("keyPassword");
47 | public static final BString PATH = StringUtils.fromString("path");
48 | public static final BString PASSWORD = StringUtils.fromString("password");
49 |
50 | public static final String TLS = "TLS";
51 | public static final String PKCS12 = "PKCS12";
52 | public static final String HTTP_2 = "HTTP_2";
53 |
54 | public static final String NATIVE_DATA_PUBLIC_KEY_CERTIFICATE = "NATIVE_DATA_PUBLIC_KEY_CERTIFICATE";
55 | public static final String NATIVE_DATA_PRIVATE_KEY = "NATIVE_DATA_PRIVATE_KEY";
56 |
57 | public static final String RUNTIME_WARNING_PREFIX = "warning: [ballerina/jwt] ";
58 | public static final String HTTPS_RECOMMENDATION_ERROR = "HTTPS is recommended but using HTTP";
59 | }
60 |
--------------------------------------------------------------------------------
/examples/order-management-service/inventory_service/modules/inventory/inventory.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2021, 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 | type ElectronicItem record {|
18 | readonly string code;
19 | string brand;
20 | string model;
21 | string price;
22 | int qty;
23 | |};
24 |
25 | type BookItem record {|
26 | readonly string code;
27 | string title;
28 | string authors;
29 | string price;
30 | int qty;
31 | |};
32 |
33 | table key(code) electronicsTable = table [
34 | {
35 | "code": "APMBA132021",
36 | "brand": "Apple",
37 | "model": "Mac Book AIR M1 (13-inch 2021)",
38 | "price": "$1249.00",
39 | "qty": 32
40 | },
41 | {
42 | "code": "SOWH1000XM4",
43 | "brand": "Sony",
44 | "model": "WH-1000XM4",
45 | "price": "$349.99",
46 | "qty": 75
47 | }
48 | ];
49 |
50 | table key(code) booksTable = table [
51 | {
52 | "code": "978-1617295959",
53 | "title": "Microservices Security in Action",
54 | "authors": "Prabath Siriwardena and Nuwan Dias",
55 | "price": "$50.99",
56 | "qty": 10
57 | },
58 | {
59 | "code": "978-1484220498",
60 | "title": "Advanced API Security",
61 | "authors": "Prabath Siriwardena",
62 | "price": "$15.39",
63 | "qty": 10
64 | }
65 | ];
66 |
67 | public type InventoryItem ElectronicItem|BookItem;
68 |
69 | public map> inventory = {
70 | electronics: electronicsTable,
71 | books: booksTable
72 | };
73 |
74 | public function increaseQty(string itemCategory, string itemCode, int qty) {
75 | InventoryItem item = filterInventoryItem(itemCategory, itemCode);
76 | item.qty += qty;
77 | }
78 |
79 | public function decreaseQty(string itemCategory, string itemCode, int qty) {
80 | InventoryItem item = filterInventoryItem(itemCategory, itemCode);
81 | item.qty -= qty;
82 | }
83 |
84 | function filterInventoryItem(string itemCategory, string itemCode) returns InventoryItem {
85 | table key(code) inventoryTable = key(code)>inventory[itemCategory];
86 | return inventoryTable.get(itemCode);
87 | }
88 |
--------------------------------------------------------------------------------
/compiler-plugin/build.gradle:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * Copyright (c) 2025, WSO2 LLC. (http://www.wso2.org)
4 | *
5 | * WSO2 LLC. licenses this file to you under the Apache License,
6 | * Version 2.0 (the "License"); you may not use this file except
7 | * in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 |
20 | plugins {
21 | id 'java'
22 | id 'checkstyle'
23 | id 'com.github.spotbugs'
24 | }
25 |
26 | description = 'Ballerina - JWT Compiler Plugin'
27 |
28 |
29 | dependencies {
30 | checkstyle project(':checkstyle')
31 | checkstyle "com.puppycrawl.tools:checkstyle:${checkstylePluginVersion}"
32 |
33 | implementation group: 'org.ballerinalang', name: 'ballerina-lang', version: "${ballerinaLangVersion}"
34 | implementation group: 'org.ballerinalang', name: 'ballerina-tools-api', version: "${ballerinaLangVersion}"
35 | implementation group: 'org.ballerinalang', name: 'ballerina-parser', version: "${ballerinaLangVersion}"
36 | implementation group: 'io.ballerina.scan', name: 'scan-command', version: "${balScanVersion}"
37 | implementation project(":jwt-native")
38 | }
39 |
40 | def excludePattern = '**/module-info.java'
41 | tasks.withType(Checkstyle).configureEach {
42 | exclude excludePattern
43 | }
44 |
45 | checkstyle {
46 | toolVersion "${project.checkstylePluginVersion}"
47 | configFile rootProject.file("build-config/checkstyle/build/checkstyle.xml")
48 | configProperties = ["suppressionFile" : file("${rootDir}/build-config/checkstyle/build/suppressions.xml")]
49 | }
50 |
51 | checkstyleMain.dependsOn(":checkstyle:downloadCheckstyleRuleFiles")
52 |
53 | spotbugsMain {
54 | def classLoader = plugins["com.github.spotbugs"].class.classLoader
55 | def SpotBugsConfidence = classLoader.findLoadedClass("com.github.spotbugs.snom.Confidence")
56 | def SpotBugsEffort = classLoader.findLoadedClass("com.github.spotbugs.snom.Effort")
57 | effort = SpotBugsEffort.MAX
58 | reportLevel = SpotBugsConfidence.LOW
59 | reportsDir = file("$project.buildDir/reports/spotbugs")
60 | reports {
61 | html.enabled true
62 | text.enabled = true
63 | }
64 | def excludeFile = file("${rootDir}/spotbugs-exclude.xml")
65 | if(excludeFile.exists()) {
66 | excludeFilter = excludeFile
67 | }
68 | }
69 |
70 | compileJava {
71 | doFirst {
72 | options.compilerArgs = [
73 | '--module-path', classpath.asPath,
74 | ]
75 | classpath = files()
76 | }
77 | }
78 |
79 | build.dependsOn ":jwt-native:build"
80 |
--------------------------------------------------------------------------------
/changelog.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 | This file contains all the notable changes done to the Ballerina JWT package through the releases.
3 |
4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
5 |
6 | ## [2.15.1] - 2025-10-03
7 |
8 | ### Added
9 |
10 | - [Add support for scan rule to detect 'NONE' algorithm type](https://github.com/ballerina-platform/ballerina-library/issues/7918)
11 | - [Add support to directly provide `crypto:PrivateKey` and `crypto:PublicKey` in JWT signature configurations](https://github.com/ballerina-platform/ballerina-library/issues/6514)
12 |
13 | ## [2.12.1] - 2024-06-14
14 |
15 | ## Changed
16 | - [Revert support to directly provide `crypto:PrivateKey` and `crypto:PublicKey` in JWT signature configurations](https://github.com/ballerina-platform/ballerina-library/issues/6628)
17 |
18 | ## [2.12.0] - 2024-05-31
19 |
20 | ### Added
21 | - [Add support to directly provide `crypto:PrivateKey` and `crypto:PublicKey` in JWT signature configurations](https://github.com/ballerina-platform/ballerina-library/issues/6514)
22 |
23 | ## [2.5.0] - 2022-11-29
24 |
25 | ### Changed
26 | - [API Docs Updated](https://github.com/ballerina-platform/ballerina-standard-library/issues/3463)
27 |
28 | ## [2.3.0] - 2022-05-30
29 |
30 | ### Changed
31 | - [Append the scheme of the HTTP client URL (JWKs) based on the client configurations](https://github.com/ballerina-platform/ballerina-standard-library/issues/2816)
32 |
33 | ## [2.0.0] - 2021-10-10
34 |
35 | ### Added
36 | - [Add HMAC signature support for JWT](https://github.com/ballerina-platform/ballerina-standard-library/issues/1645)
37 |
38 | ## [1.1.0-beta2] - 2021-07-06
39 |
40 | ### Added
41 | - [Improve JWT validation for all the fields of JWT issuer configuration](https://github.com/ballerina-platform/ballerina-standard-library/issues/1240)
42 |
43 | ## [1.1.0-alpha8] - 2021-04-22
44 |
45 | ### Changed
46 | - [Improve error messages and log messages](https://github.com/ballerina-platform/ballerina-standard-library/issues/1242)
47 |
48 | ## [1.1.0-alpha6] - 2021-04-02
49 |
50 | ### Changed
51 | - Remove usages of `checkpanic` for type narrowing
52 |
53 | ## [1.1.0-alpha5] - 2021-03-19
54 |
55 | ### Added
56 | - [Add cert file and mTLS support for JDK11 client](https://github.com/ballerina-platform/ballerina-standard-library/issues/936)
57 | - [Add jti claim as a user input](https://github.com/ballerina-platform/ballerina-standard-library/issues/1210)
58 |
59 | ### Changed
60 | - [Replace base64 URL encode/decode APIs](https://github.com/ballerina-platform/ballerina-standard-library/issues/1212)
61 | - Update error types and log API
62 | - Update for Time API changes
63 |
64 | ### Fixed
65 | - Fix nbf/exp claim validation
66 |
67 | ## [1.1.0-alpha4] - 2021-02-20
68 |
69 | ### Changed
70 | - [Refactor JWT validating API](https://github.com/ballerina-platform/ballerina-standard-library/issues/1213)
71 | - Refactor JWT issue/validate test cases
72 | - Update for crypto API changes
73 | - [Extend private key/public cert support for JWT signature generation/validation](https://github.com/ballerina-platform/ballerina-standard-library/issues/822)
74 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%"=="" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%"=="" set DIRNAME=.
29 | @rem This is normally unused
30 | set APP_BASE_NAME=%~n0
31 | set APP_HOME=%DIRNAME%
32 |
33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
35 |
36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
38 |
39 | @rem Find java.exe
40 | if defined JAVA_HOME goto findJavaFromJavaHome
41 |
42 | set JAVA_EXE=java.exe
43 | %JAVA_EXE% -version >NUL 2>&1
44 | if %ERRORLEVEL% equ 0 goto execute
45 |
46 | echo.
47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
48 | echo.
49 | echo Please set the JAVA_HOME variable in your environment to match the
50 | echo location of your Java installation.
51 |
52 | goto fail
53 |
54 | :findJavaFromJavaHome
55 | set JAVA_HOME=%JAVA_HOME:"=%
56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
57 |
58 | if exist "%JAVA_EXE%" goto execute
59 |
60 | echo.
61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
62 | echo.
63 | echo Please set the JAVA_HOME variable in your environment to match the
64 | echo location of your Java installation.
65 |
66 | goto fail
67 |
68 | :execute
69 | @rem Setup the command line
70 |
71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
72 |
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if %ERRORLEVEL% equ 0 goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | set EXIT_CODE=%ERRORLEVEL%
85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
87 | exit /b %EXIT_CODE%
88 |
89 | :mainEnd
90 | if "%OS%"=="Windows_NT" endlocal
91 |
92 | :omega
93 |
--------------------------------------------------------------------------------
/docs/proposals/enable-crypto-key-usage.md:
--------------------------------------------------------------------------------
1 | # Proposal: Enable direct use of `crypto:PrivateKey` and `crypto:PublicKey` in JWT signature configurations
2 |
3 | _Authors_: @ayeshLK \
4 | _Reviewers_: @shafreenAnfar @daneshk @NipunaRanasinghe @Bhashinee \
5 | _Created_: 2024/05/08 \
6 | _Updated_: 2024/05/08 \
7 | _Issue_: [#6515](https://github.com/ballerina-platform/ballerina-library/issues/6515)
8 |
9 | ## Summary
10 |
11 | JWT signature configurations are designed to facilitate the generation and verification of JWT signatures.
12 | Therefore, the JWT package should support direct usage of `crypto:PrivateKey` and `crypto:PublicKey` in
13 | `jwt:IssuerSignatureConfig` and `jwt:ValidatorSignatureConfig` respectively.
14 | ## Goals
15 |
16 | - Enable direct use of `crypto:PrivateKey` and `crypto:PublicKey` in JWT signature configurations
17 |
18 | ## Motivation
19 |
20 | JWT signature configurations are required configurations to generate the signature portion of a JWT. Typically,
21 | these configurations involve a private key and a public certificate. In Ballerina, these elements are represented as
22 | `crypto:PrivateKey` and `crypto:PublicKey`, respectively. Therefore, JWT signature configurations should allow the
23 | direct usage of `crypto:PrivateKey` and `crypto:PublicKey` within its API.
24 |
25 | ## Description
26 |
27 | As mentioned in the Goals section the purpose of this proposal is to enable direct use of `crypto:PrivateKey`
28 | and `crypto:PublicKey` in JWT signature configurations.
29 |
30 | The key functionalities expected from this change are as follows,
31 |
32 | - Allow `crypto:PrivateKey` and `crypto:PublicKey` in `jwt:IssuerSignatureConfig` and `jwt:ValidatorSignatureConfig` respectively.
33 |
34 | ### API changes
35 |
36 | Add support for `crypto:PrivateKey` in the `config` field of `jwt:IssuerSignatureConfig` record.
37 |
38 | ```ballerina
39 | # Represents JWT signature configurations.
40 | #
41 | # + algorithm - Cryptographic signing algorithm for JWS
42 | # + config - KeyStore configurations, private key configurations or shared key configurations
43 | public type IssuerSignatureConfig record {|
44 | SigningAlgorithm algorithm = RS256;
45 | record {|
46 | crypto:KeyStore keyStore;
47 | string keyAlias;
48 | string keyPassword;
49 | |} | record {|
50 | string keyFile;
51 | string keyPassword?;
52 | |}|crypto:PrivateKey|string config?;
53 | |};
54 | ```
55 |
56 | Add support for `crypto:PublicKey` in the `certFile` field of `jwt:ValidatorSignatureConfig` record.
57 |
58 | ```ballerina
59 | # Represents JWT signature configurations.
60 | #
61 | # + jwksConfig - JWKS configurations
62 | # + certFile - Public certificate file
63 | # + trustStoreConfig - JWT TrustStore configurations
64 | # + secret - HMAC secret configuration
65 | public type ValidatorSignatureConfig record {|
66 | record {|
67 | string url;
68 | cache:CacheConfig cacheConfig?;
69 | ClientConfiguration clientConfig = {};
70 | |} jwksConfig?;
71 | string|crypto:PublicKey certFile?;
72 | record {|
73 | crypto:TrustStore trustStore;
74 | string certAlias;
75 | |} trustStoreConfig?;
76 | string secret?;
77 | |};
78 | ```
79 |
80 | ## Dependencies
81 |
82 | - [#6513](https://github.com/ballerina-platform/ballerina-library/issues/6513)
83 |
--------------------------------------------------------------------------------
/ballerina/jwt_commons.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 | import ballerina/jballerina.java;
18 |
19 | # Represents the cryptographic algorithms used to secure the JWS.
20 | public type SigningAlgorithm RS256|RS384|RS512|HS256|HS384|HS512|NONE;
21 |
22 | # The `RSA-SHA256` algorithm.
23 | public const RS256 = "RS256";
24 |
25 | # The `RSA-SHA384` algorithm.
26 | public const RS384 = "RS384";
27 |
28 | # The `RSA-SHA512` algorithm.
29 | public const RS512 = "RS512";
30 |
31 | # The `HMAC-SHA256` algorithm.
32 | public const HS256 = "HS256";
33 |
34 | # The `HMAC-SHA384` algorithm.
35 | public const HS384 = "HS384";
36 |
37 | # The `HMAC-SHA512` algorithm.
38 | public const HS512 = "HS512";
39 |
40 | # Unsecured JWS (no signing).
41 | public const NONE = "none";
42 |
43 | //JOSH header parameters
44 | const string ALG = "alg";
45 | const string TYP = "typ";
46 | const string CTY = "cty";
47 | const string KID = "kid";
48 |
49 | //Payload parameters
50 | const string ISS = "iss";
51 | const string SUB = "sub";
52 | const string AUD = "aud";
53 | const string JTI = "jti";
54 | const string EXP = "exp";
55 | const string NBF = "nbf";
56 | const string IAT = "iat";
57 |
58 | # Represents JWT header.
59 | #
60 | # + alg - Cryptographic algorithm used to secure the JWS. Supported values: `RS256`, `RS384`, `RS512`, `HS256`, `HS384`, `HS512`, `NONE`.
61 | # + typ - Media type of the JWT
62 | # + cty - Content type, conveys structural information about the JWT
63 | # + kid - Key ID, a hint indicating which key was used to secure the JWS
64 | public type Header record {
65 | SigningAlgorithm alg?;
66 | string typ?;
67 | string cty?;
68 | string kid?;
69 | };
70 |
71 | # Represents JWT payload.
72 | #
73 | # + iss - Issuer, identifies the principal that issued the JWT
74 | # + sub - Subject, identifies the principal that is the subject of the JWT
75 | # + aud - Audience, identifies the recipients that the JWT is intended for
76 | # + jti - JWT ID, unique identifier for the JWT
77 | # + exp - Expiration time, identifies the expiration time (in seconds since the Epoch) on or after which the JWT must not be accepted
78 | # + nbf - Not before, identifies the time (in seconds since the Epoch) before which the JWT must not be accepted
79 | # + iat - Issued at, identifies the time (in seconds since the Epoch) at which the JWT was issued
80 | public type Payload record {
81 | string iss?;
82 | string sub?;
83 | string|string[] aud?;
84 | int exp?;
85 | int nbf?;
86 | int iat?;
87 | string jti?;
88 | };
89 |
90 | isolated function encodeBase64Url(byte[] input) returns string = @java:Method {
91 | 'class: "io.ballerina.stdlib.jwt.JwtUtils"
92 | } external;
93 |
94 | isolated function decodeBase64Url(string input) returns byte[]|Error = @java:Method {
95 | 'class: "io.ballerina.stdlib.jwt.JwtUtils"
96 | } external;
97 |
--------------------------------------------------------------------------------
/compiler-plugin-tests/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2025, WSO2 LLC. (http://www.wso2.org)
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 | plugins {
20 | id 'java'
21 | id 'checkstyle'
22 | id 'com.github.spotbugs'
23 | }
24 |
25 | description = 'Ballerina - JWT Compiler Plugin Tests'
26 |
27 | dependencies {
28 | checkstyle project(':checkstyle')
29 | checkstyle "com.puppycrawl.tools:checkstyle:${checkstylePluginVersion}"
30 |
31 | implementation project(':jwt-compiler-plugin')
32 |
33 | testImplementation group: 'org.ballerinalang', name: 'ballerina-lang', version: "${ballerinaLangVersion}"
34 | testImplementation group: 'org.ballerinalang', name: 'ballerina-tools-api', version: "${ballerinaLangVersion}"
35 | testImplementation group: 'org.ballerinalang', name: 'ballerina-parser', version: "${ballerinaLangVersion}"
36 | testImplementation group: 'io.ballerina.scan', name: 'scan-command', version: "${balScanVersion}"
37 | testImplementation group: 'io.ballerina.scan', name: 'scan-command-test-utils', version: "${balScanVersion}"
38 | testImplementation group: 'org.testng', name: 'testng', version: "${testngVersion}"
39 | testImplementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "${jacksonDatabindVersion}"
40 | }
41 | tasks.withType(JavaCompile).configureEach {
42 | options.encoding = 'UTF-8'
43 | }
44 |
45 | sourceCompatibility = JavaVersion.VERSION_21
46 |
47 | test {
48 | systemProperty "ballerina.offline.flag", "true"
49 | useTestNG() {
50 | suites 'src/test/resources/testng.xml'
51 | }
52 | testLogging.showStandardStreams = true
53 | testLogging {
54 | events "PASSED", "FAILED", "SKIPPED"
55 | afterSuite { desc, result ->
56 | if (!desc.parent) { // will match the outermost suite
57 | def output = "Results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)"
58 | def startItem = '| ', endItem = ' |'
59 | def repeatLength = startItem.length() + output.length() + endItem.length()
60 | println('\n' + ('-' * repeatLength) + '\n' + startItem + output + endItem + '\n' + ('-' * repeatLength))
61 | }
62 | }
63 | }
64 | }
65 |
66 | spotbugsTest {
67 | def classLoader = plugins["com.github.spotbugs"].class.classLoader
68 | def SpotBugsConfidence = classLoader.findLoadedClass("com.github.spotbugs.snom.Confidence")
69 | def SpotBugsEffort = classLoader.findLoadedClass("com.github.spotbugs.snom.Effort")
70 | ignoreFailures = true
71 | effort = SpotBugsEffort.MAX
72 | reportLevel = SpotBugsConfidence.LOW
73 | reportsDir = file("$project.buildDir/reports/spotbugs")
74 | def excludeFile = file("${rootDir}/build-config/spotbugs-exclude.xml")
75 | if (excludeFile.exists()) {
76 | it.excludeFilter = excludeFile
77 | }
78 | reports {
79 | text.enabled = true
80 | }
81 | }
82 |
83 | spotbugsMain {
84 | enabled false
85 | }
86 |
87 | tasks.register('validateSpotbugs') {
88 | doLast {
89 | if (spotbugsMain.reports.size() > 0 &&
90 | spotbugsMain.reports[0].destination.exists() &&
91 | spotbugsMain.reports[0].destination.text.readLines().size() > 0) {
92 | spotbugsMain.reports[0].destination?.eachLine {
93 | println 'Failure: ' + it
94 | }
95 | throw new GradleException("Spotbugs rule violations were found.");
96 | }
97 | }
98 | }
99 |
100 | tasks.withType(Checkstyle).configureEach {
101 | exclude '**/module-info.java'
102 | }
103 |
104 | checkstyle {
105 | toolVersion "${project.checkstylePluginVersion}"
106 | configFile rootProject.file("build-config/checkstyle/build/checkstyle.xml")
107 | configProperties = ["suppressionFile": file("${rootDir}/build-config/checkstyle/build/suppressions.xml")]
108 | }
109 |
110 | checkstyleMain {
111 | enabled false
112 | }
113 |
114 | spotbugsTest.finalizedBy validateSpotbugs
115 | checkstyleTest.dependsOn ':checkstyle:downloadCheckstyleRuleFiles'
116 |
117 | compileJava {
118 | doFirst {
119 | options.compilerArgs = [
120 | '--module-path', classpath.asPath,
121 | ]
122 | classpath = files()
123 | }
124 | }
125 |
126 | test.dependsOn ":jwt-ballerina:build"
127 | build.dependsOn ":jwt-ballerina:build"
128 |
--------------------------------------------------------------------------------
/ballerina/tests/listener_jwt_auth_provider_test.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 | // NOTE: All the tokens/credentials used in this test are dummy tokens/credentials and used only for testing purposes.
18 |
19 | import ballerina/cache;
20 | import ballerina/test;
21 |
22 | @test:Config {}
23 | isolated function testListenerJwtAuthProviderSuccess() returns Error? {
24 | ValidatorConfig jwtConfig = {
25 | issuer: "wso2",
26 | audience: "ballerina",
27 | cacheConfig: {
28 | capacity: 10,
29 | evictionFactor: 0.25,
30 | evictionPolicy: cache:LRU,
31 | defaultMaxAge: -1,
32 | cleanupInterval: 3600
33 | },
34 | signatureConfig: {
35 | trustStoreConfig: {
36 | trustStore: {
37 | path: TRUSTSTORE_PATH,
38 | password: "ballerina"
39 | },
40 | certAlias: "ballerina"
41 | }
42 | }
43 | };
44 | ListenerJwtAuthProvider jwtAuthProvider = new(jwtConfig);
45 | Payload result = check jwtAuthProvider.authenticate(JWT1);
46 | test:assertEquals(result?.iss, "wso2");
47 | test:assertEquals(result?.aud, ["ballerina","ballerinaSamples"]);
48 | // Authenticate the token from the cache
49 | result = check jwtAuthProvider.authenticate(JWT1);
50 | test:assertEquals(result?.iss, "wso2");
51 | test:assertEquals(result?.aud, ["ballerina","ballerinaSamples"]);
52 | }
53 |
54 | @test:Config {
55 | groups: ["jwks"]
56 | }
57 | isolated function testListenerJwtAuthProviderSuccessWithJwk() returns Error? {
58 | ValidatorConfig jwtConfig = {
59 | issuer: "ballerina",
60 | audience: "vEwzbcasJVQm1jVYHUHCjhxZ4tYa",
61 | cacheConfig: {
62 | capacity: 10,
63 | evictionFactor: 0.25,
64 | evictionPolicy: cache:LRU,
65 | defaultMaxAge: -1,
66 | cleanupInterval: 3600
67 | },
68 | signatureConfig: {
69 | jwksConfig: {
70 | url: "https://localhost:9445/oauth2/jwks",
71 | cacheConfig: {
72 | capacity: 10,
73 | evictionFactor: 0.25,
74 | evictionPolicy: cache:LRU,
75 | defaultMaxAge: -1,
76 | cleanupInterval: 3600
77 | },
78 | clientConfig: {
79 | secureSocket: {
80 | cert: {
81 | path: TRUSTSTORE_PATH,
82 | password: "ballerina"
83 | }
84 | }
85 | }
86 | }
87 | }
88 | };
89 | ListenerJwtAuthProvider jwtAuthProvider = new(jwtConfig);
90 | Payload result = check jwtAuthProvider.authenticate(JWT2);
91 | test:assertEquals(result?.iss, "ballerina");
92 | test:assertEquals(result?.aud, ["vEwzbcasJVQm1jVYHUHCjhxZ4tYa"]);
93 | }
94 |
95 | @test:Config {}
96 | isolated function testListenerJwtAuthProviderFailure() {
97 | ValidatorConfig jwtConfig = {
98 | issuer: "invalid",
99 | audience: "ballerina",
100 | signatureConfig: {
101 | trustStoreConfig: {
102 | trustStore: {
103 | path: TRUSTSTORE_PATH,
104 | password: "ballerina"
105 | },
106 | certAlias: "ballerina"
107 | }
108 | }
109 | };
110 | ListenerJwtAuthProvider jwtAuthProvider = new(jwtConfig);
111 | Payload|Error result = jwtAuthProvider.authenticate(JWT1);
112 | if result is Error {
113 | test:assertEquals(result.message(), "JWT validation failed.");
114 | } else {
115 | test:assertFail("Expected error not found.");
116 | }
117 | }
118 |
119 | @test:Config {}
120 | isolated function testListenerJwtAuthProviderFailureWithInvalidCredential() {
121 | ValidatorConfig jwtConfig = {
122 | issuer: "wso2",
123 | audience: "ballerina",
124 | signatureConfig: {
125 | trustStoreConfig: {
126 | trustStore: {
127 | path: TRUSTSTORE_PATH,
128 | password: "ballerina"
129 | },
130 | certAlias: "ballerina"
131 | }
132 | }
133 | };
134 | ListenerJwtAuthProvider jwtAuthProvider = new(jwtConfig);
135 | Payload|Error result = jwtAuthProvider.authenticate("invalid_credential");
136 | if result is Error {
137 | test:assertEquals(result.message(), "Credential format does not match to JWT format.");
138 | } else {
139 | test:assertFail("Expected error not found.");
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/ballerina/Dependencies.toml:
--------------------------------------------------------------------------------
1 | # AUTO-GENERATED FILE. DO NOT MODIFY.
2 |
3 | # This file is auto-generated by Ballerina for managing dependency versions.
4 | # It should not be modified by hand.
5 |
6 | [ballerina]
7 | dependencies-toml-version = "2"
8 | distribution-version = "2201.12.0"
9 |
10 | [[package]]
11 | org = "ballerina"
12 | name = "cache"
13 | version = "3.10.0"
14 | dependencies = [
15 | {org = "ballerina", name = "constraint"},
16 | {org = "ballerina", name = "jballerina.java"},
17 | {org = "ballerina", name = "task"},
18 | {org = "ballerina", name = "time"}
19 | ]
20 | modules = [
21 | {org = "ballerina", packageName = "cache", moduleName = "cache"}
22 | ]
23 |
24 | [[package]]
25 | org = "ballerina"
26 | name = "constraint"
27 | version = "1.7.0"
28 | dependencies = [
29 | {org = "ballerina", name = "jballerina.java"}
30 | ]
31 |
32 | [[package]]
33 | org = "ballerina"
34 | name = "crypto"
35 | version = "2.9.0"
36 | dependencies = [
37 | {org = "ballerina", name = "jballerina.java"},
38 | {org = "ballerina", name = "time"}
39 | ]
40 | modules = [
41 | {org = "ballerina", packageName = "crypto", moduleName = "crypto"}
42 | ]
43 |
44 | [[package]]
45 | org = "ballerina"
46 | name = "io"
47 | version = "1.8.0"
48 | dependencies = [
49 | {org = "ballerina", name = "jballerina.java"},
50 | {org = "ballerina", name = "lang.value"}
51 | ]
52 | modules = [
53 | {org = "ballerina", packageName = "io", moduleName = "io"}
54 | ]
55 |
56 | [[package]]
57 | org = "ballerina"
58 | name = "jballerina.java"
59 | version = "0.0.0"
60 | modules = [
61 | {org = "ballerina", packageName = "jballerina.java", moduleName = "jballerina.java"}
62 | ]
63 |
64 | [[package]]
65 | org = "ballerina"
66 | name = "jwt"
67 | version = "2.15.1"
68 | dependencies = [
69 | {org = "ballerina", name = "cache"},
70 | {org = "ballerina", name = "crypto"},
71 | {org = "ballerina", name = "io"},
72 | {org = "ballerina", name = "jballerina.java"},
73 | {org = "ballerina", name = "lang.int"},
74 | {org = "ballerina", name = "lang.string"},
75 | {org = "ballerina", name = "log"},
76 | {org = "ballerina", name = "test"},
77 | {org = "ballerina", name = "time"}
78 | ]
79 | modules = [
80 | {org = "ballerina", packageName = "jwt", moduleName = "jwt"}
81 | ]
82 |
83 | [[package]]
84 | org = "ballerina"
85 | name = "lang.__internal"
86 | version = "0.0.0"
87 | dependencies = [
88 | {org = "ballerina", name = "jballerina.java"},
89 | {org = "ballerina", name = "lang.object"}
90 | ]
91 |
92 | [[package]]
93 | org = "ballerina"
94 | name = "lang.array"
95 | version = "0.0.0"
96 | scope = "testOnly"
97 | dependencies = [
98 | {org = "ballerina", name = "jballerina.java"},
99 | {org = "ballerina", name = "lang.__internal"}
100 | ]
101 |
102 | [[package]]
103 | org = "ballerina"
104 | name = "lang.error"
105 | version = "0.0.0"
106 | scope = "testOnly"
107 | dependencies = [
108 | {org = "ballerina", name = "jballerina.java"}
109 | ]
110 |
111 | [[package]]
112 | org = "ballerina"
113 | name = "lang.int"
114 | version = "0.0.0"
115 | dependencies = [
116 | {org = "ballerina", name = "jballerina.java"},
117 | {org = "ballerina", name = "lang.__internal"},
118 | {org = "ballerina", name = "lang.object"}
119 | ]
120 | modules = [
121 | {org = "ballerina", packageName = "lang.int", moduleName = "lang.int"}
122 | ]
123 |
124 | [[package]]
125 | org = "ballerina"
126 | name = "lang.object"
127 | version = "0.0.0"
128 |
129 | [[package]]
130 | org = "ballerina"
131 | name = "lang.regexp"
132 | version = "0.0.0"
133 | dependencies = [
134 | {org = "ballerina", name = "jballerina.java"}
135 | ]
136 |
137 | [[package]]
138 | org = "ballerina"
139 | name = "lang.string"
140 | version = "0.0.0"
141 | dependencies = [
142 | {org = "ballerina", name = "jballerina.java"},
143 | {org = "ballerina", name = "lang.regexp"}
144 | ]
145 | modules = [
146 | {org = "ballerina", packageName = "lang.string", moduleName = "lang.string"}
147 | ]
148 |
149 | [[package]]
150 | org = "ballerina"
151 | name = "lang.value"
152 | version = "0.0.0"
153 | dependencies = [
154 | {org = "ballerina", name = "jballerina.java"}
155 | ]
156 |
157 | [[package]]
158 | org = "ballerina"
159 | name = "log"
160 | version = "2.12.0"
161 | dependencies = [
162 | {org = "ballerina", name = "io"},
163 | {org = "ballerina", name = "jballerina.java"},
164 | {org = "ballerina", name = "lang.value"},
165 | {org = "ballerina", name = "observe"}
166 | ]
167 | modules = [
168 | {org = "ballerina", packageName = "log", moduleName = "log"}
169 | ]
170 |
171 | [[package]]
172 | org = "ballerina"
173 | name = "observe"
174 | version = "1.5.0"
175 | dependencies = [
176 | {org = "ballerina", name = "jballerina.java"}
177 | ]
178 |
179 | [[package]]
180 | org = "ballerina"
181 | name = "task"
182 | version = "2.7.0"
183 | dependencies = [
184 | {org = "ballerina", name = "jballerina.java"},
185 | {org = "ballerina", name = "time"}
186 | ]
187 |
188 | [[package]]
189 | org = "ballerina"
190 | name = "test"
191 | version = "0.0.0"
192 | scope = "testOnly"
193 | dependencies = [
194 | {org = "ballerina", name = "jballerina.java"},
195 | {org = "ballerina", name = "lang.array"},
196 | {org = "ballerina", name = "lang.error"}
197 | ]
198 | modules = [
199 | {org = "ballerina", packageName = "test", moduleName = "test"}
200 | ]
201 |
202 | [[package]]
203 | org = "ballerina"
204 | name = "time"
205 | version = "2.7.0"
206 | dependencies = [
207 | {org = "ballerina", name = "jballerina.java"}
208 | ]
209 | modules = [
210 | {org = "ballerina", packageName = "time", moduleName = "time"}
211 | ]
212 |
213 |
--------------------------------------------------------------------------------
/examples/order-management-service/order_service/order_service.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2021, 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 | import ballerina/cache;
18 | import ballerina/http;
19 | import order_service.representations as rep;
20 |
21 | // In memory storage used to store the orders
22 | map ordersMap = {};
23 |
24 | http:Client inventoryClient = check new ("https://localhost:9091",
25 | secureSocket = {
26 | cert: "./resources/public.crt",
27 | key: {
28 | certFile: "./resources/public.crt",
29 | keyFile: "./resources/private.key"
30 | }
31 | }
32 | );
33 |
34 | http:JwtValidatorConfig config = {
35 | issuer: "wso2",
36 | audience: "ballerina",
37 | signatureConfig: {
38 | jwksConfig: {
39 | url: "https://localhost:9445/oauth2/jwks",
40 | clientConfig: {
41 | secureSocket: {
42 | cert: "./resources/public.crt"
43 | }
44 | },
45 | cacheConfig: {
46 | capacity: 10,
47 | evictionFactor: 0.25,
48 | evictionPolicy: cache:LRU,
49 | defaultMaxAge: -1
50 | }
51 | }
52 | },
53 | cacheConfig: {
54 | capacity: 10,
55 | evictionFactor: 0.25,
56 | evictionPolicy: cache:LRU,
57 | defaultMaxAge: -1
58 | }
59 | };
60 |
61 | listener http:Listener orderEP = new (9090,
62 | secureSocket = {
63 | key: {
64 | certFile: "./resources/public.crt",
65 | keyFile: "./resources/private.key"
66 | }
67 | }
68 | );
69 |
70 | service /'order on orderEP {
71 |
72 | @http:ResourceConfig {
73 | auth: [
74 | {
75 | jwtValidatorConfig: config,
76 | scopes: "add_order"
77 | }
78 | ]
79 | }
80 | resource function post .(@http:Payload rep:Order 'order) returns rep:OrderCreated|error {
81 | string orderId = 'order.id;
82 | ordersMap[orderId] = 'order;
83 | check updateInventoryQty('order.items, rep:DECREASE);
84 | return {
85 | body: {status: "Order '" + orderId + "' created."},
86 | headers: {"Location": "http://localhost:9090/order/" + orderId}
87 | };
88 | }
89 |
90 | @http:ResourceConfig {
91 | auth: [
92 | {
93 | jwtValidatorConfig: config,
94 | scopes: "update_order"
95 | }
96 | ]
97 | }
98 | resource function put [string orderId](@http:Payload rep:UpdateOrder updateOrder)
99 | returns rep:OrderUpdated|rep:OrderNotFound|error {
100 | rep:Order? existingOrder = ordersMap[orderId];
101 | if existingOrder is rep:Order {
102 | check updateInventoryQty(existingOrder.items, rep:INCREASE);
103 | existingOrder.name = updateOrder.name;
104 | existingOrder.items = updateOrder.items;
105 | ordersMap[orderId] = existingOrder;
106 | check updateInventoryQty(existingOrder.items, rep:DECREASE);
107 | return {
108 | body: {status: "Order '" + orderId + "' updated."}
109 | };
110 | }
111 | return {
112 | body: {status: "Order '" + orderId + "' cannot be found."}
113 | };
114 | }
115 |
116 | @http:ResourceConfig {
117 | auth: [
118 | {
119 | jwtValidatorConfig: config,
120 | scopes: "cancel_order"
121 | }
122 | ]
123 | }
124 | resource function delete [string orderId]() returns rep:OrderCanceled|rep:OrderNotFound|error {
125 | if ordersMap.hasKey(orderId) {
126 | rep:Order 'order = ordersMap.remove(orderId);
127 | check updateInventoryQty('order.items, rep:INCREASE);
128 | return {
129 | body: {status: "Order '" + orderId + "' removed."}
130 | };
131 | }
132 | return {
133 | body: {status: "Order '" + orderId + "' cannot be found."}
134 | };
135 | }
136 |
137 | resource function get [string orderId]() returns rep:Order|http:NotFound {
138 | if ordersMap.hasKey(orderId) {
139 | return ordersMap[orderId];
140 | }
141 | return {body: {status: "Order '" + orderId + "' cannot be found."}};
142 | }
143 | }
144 |
145 | function updateInventoryQty(rep:OrderItem[] items, rep:InventoryOperation operation) returns error? {
146 | json|http:ClientError response = inventoryClient->put("/inventory/" + operation, items);
147 | if response is http:ClientError {
148 | return error("Failed to " + operation + " the inventory quantity.", response);
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/load-tests/order_management_service/scripts/http-post-request.jmx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | false
7 | true
8 | false
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | continue
17 |
18 | false
19 | -1
20 |
21 | ${__P(users)}
22 | ${__P(rampUpPeriod,60)}
23 | true
24 | ${__P(duration)}
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | ${__P(payload)}
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | ${__P(host,localhost)}
42 | ${__P(port,9090)}
43 | ${__P(protocol,http)}
44 |
45 | ${__P(path)}
46 | POST
47 | true
48 | false
49 | true
50 | false
51 |
52 | HttpClient4
53 | 10000
54 | 120000
55 |
56 |
57 |
58 |
59 |
60 | Content-Type
61 | application/json
62 |
63 |
64 | Authorization
65 | Bearer eyJhbGciOiJSUzI1NiIsICJ0eXAiOiJKV1QiLCAia2lkIjoiTlRBeFptTXhORE15WkRnM01UVTFaR00wTXpFek9ESmhaV0k0TkRObFpEVTFPR0ZrTmpGaU1RIn0.eyJpc3MiOiJ3c28yIiwgInN1YiI6ImNvdW50ZXIiLCAiYXVkIjoiYmFsbGVyaW5hIiwgImV4cCI6MTk0NTIzODg5NCwgIm5iZiI6MTYyOTg3ODg5NCwgImlhdCI6MTYyOTg3ODg5NCwgImp0aSI6ImY1YWRlZDUwNTg1YzQ2ZjJiOGNhMjMzZDBjMmEzYzlkIiwgInNjb3BlIjoiYWRkX29yZGVyIn0.FMDL-Y8zMtAW7vBVeEbwf_8ynSKdjAkuEBVJpoGds06Z2cOrL3WPZYswnbUOzULBnOXQJQEnK-P-QmypvqP0NWGpzfoC5QMqg0FhPvxyglP1QNYbrS_5tZFM_7Nn7tBFZxiBq666AzjDyhZ2jc39X9rftV0m8p4yyFdSI4KFiEzQ8eOWVVOIg3ejQ0ruDlSVvwx3lXe03XYmrhQp0m-_KYm-SGV3HTZttbo00A250pVY1QL137WDgeeDtGchOfjvM9G-UL8t3sw1Lyoq4OzblHEJJQOJnfRLM_nFKeULuAtt5k_UwmQRlV-XrgxMk0lu6KvYt1-Sa1HMiS8aIvrwig
66 |
67 |
68 |
69 |
70 |
71 |
72 | ${__P(response_size)}
73 |
74 |
75 | Assertion.response_data
76 | false
77 | 16
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/ballerina/listener_jwt_auth_provider.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 | import ballerina/cache;
18 | import ballerina/log;
19 | import ballerina/time;
20 |
21 | # Represents the listener JWT Auth provider, which is used to authenticate the provided credentials (JWT) against
22 | # the provided JWT validator configurations.
23 | # ```ballerina
24 | # jwt:ListenerJwtAuthProvider provider = new({
25 | # issuer: "example",
26 | # audience: "ballerina",
27 | # signatureConfig: {
28 | # certificateAlias: "ballerina",
29 | # trustStore: {
30 | # path: "/path/to/truststore.p12",
31 | # password: "ballerina"
32 | # }
33 | # }
34 | # });
35 | # ```
36 | public isolated class ListenerJwtAuthProvider {
37 |
38 | private final ValidatorConfig & readonly validatorConfig;
39 | private final cache:Cache? jwtCache;
40 | private final cache:Cache? jwksCache;
41 |
42 | # Provides authentication based on the provided JWT.
43 | #
44 | # + validatorConfig - JWT validator configurations
45 | public isolated function init(ValidatorConfig validatorConfig) {
46 | self.validatorConfig = validatorConfig.cloneReadOnly();
47 | cache:CacheConfig? jwtCacheConfig = self.validatorConfig?.cacheConfig;
48 | if jwtCacheConfig is cache:CacheConfig {
49 | self.jwtCache = new(jwtCacheConfig);
50 | } else {
51 | self.jwtCache = ();
52 | }
53 | var jwksConfig = self.validatorConfig?.signatureConfig?.jwksConfig;
54 | if jwksConfig !is () {
55 | ClientConfiguration clientConfig = jwksConfig.clientConfig;
56 | cache:CacheConfig? jwksCacheConfig = jwksConfig?.cacheConfig;
57 | if jwksCacheConfig is cache:CacheConfig {
58 | self.jwksCache = new(jwksCacheConfig);
59 | Error? result = preloadJwksToCache( (self.jwksCache), jwksConfig.url, clientConfig);
60 | if result is Error {
61 | panic result;
62 | }
63 | return;
64 | }
65 | }
66 | self.jwksCache = ();
67 | }
68 |
69 | # Authenticates the provided JWT against the configured validator.
70 | #```ballerina
71 | # boolean result = check provider.authenticate("");
72 | # ```
73 | #
74 | # + credential - JWT to be authenticated
75 | # + return - `jwt:Payload` if authentication is successful or else a `jwt:Error` if an error occurred
76 | public isolated function authenticate(string credential) returns Payload|Error {
77 | string[] jwtComponents = re `\.`.split(credential);
78 | if jwtComponents.length() != 3 {
79 | return prepareError("Credential format does not match to JWT format.");
80 | }
81 |
82 | cache:Cache? jwtCache = self.jwtCache;
83 | if jwtCache is cache:Cache && jwtCache.hasKey(credential) {
84 | Payload? payload = validateFromCache(jwtCache, credential);
85 | if payload is Payload {
86 | return payload;
87 | }
88 | }
89 |
90 | Payload|Error validationResult = validateJwt(credential, self.validatorConfig, self.jwksCache);
91 | if validationResult is Payload {
92 | if jwtCache is cache:Cache {
93 | addToCache(jwtCache, credential, validationResult);
94 | }
95 | return validationResult;
96 | } else {
97 | return prepareError("JWT validation failed.", validationResult);
98 | }
99 | }
100 | }
101 |
102 | isolated function preloadJwksToCache(cache:Cache jwksCache, string url, ClientConfiguration clientConfig) returns Error? {
103 | string|Error stringResponse = getJwksResponse(url, clientConfig);
104 | if stringResponse is string {
105 | json[] jwksArray = check getJwksArray(stringResponse);
106 | foreach json jwk in jwksArray {
107 | json|error kid = jwk.kid;
108 | if kid is string {
109 | cache:Error? cachedResult = jwksCache.put(kid, jwk);
110 | if cachedResult is cache:Error {
111 | return prepareError("Failed to put JWK for the kid '" + kid + "' to the cache.", cachedResult);
112 | }
113 | } else if kid is error {
114 | return prepareError("Failed to access 'kid' property from the JSON '" + jwk.toString() + "'.", kid);
115 | } else {
116 | return prepareError("Failed to extract 'kid' property as a 'string' from the JSON '" + jwk.toString() + "'.");
117 | }
118 | }
119 | return;
120 | } else {
121 | return prepareError("Failed to call JWKS endpoint to preload JWKS to the cache.", stringResponse);
122 | }
123 | }
124 |
125 | isolated function validateFromCache(cache:Cache jwtCache, string jwt) returns Payload? {
126 | any|cache:Error cachedResult = jwtCache.get(jwt);
127 | if cachedResult is any {
128 | Payload payload = cachedResult;
129 | int? expTime = payload?.exp;
130 | // convert to current time and check the expiry time
131 | [int, decimal] currentTime = time:utcNow();
132 | if expTime is () || expTime > currentTime[0] {
133 | return payload;
134 | }
135 | cache:Error? result = jwtCache.invalidate(jwt);
136 | if result is cache:Error {
137 | log:printDebug("Failed to invalidate JWT from the cache.", 'error = result);
138 | }
139 | } else {
140 | log:printDebug("Failed to retrieve JWT entry from the cache.", 'error = cachedResult);
141 | }
142 | return;
143 | }
144 |
145 | isolated function addToCache(cache:Cache jwtCache, string jwt, Payload payload) {
146 | cache:Error? result = jwtCache.put(jwt, payload);
147 | if result is cache:Error {
148 | log:printDebug("Failed to add JWT to the cache.", 'error = result);
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/ballerina/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. 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 org.apache.tools.ant.taskdefs.condition.Os
20 |
21 | plugins {
22 | id 'io.ballerina.plugin'
23 | }
24 |
25 | description = 'Ballerina - JWT Ballerina Generator'
26 |
27 | def packageName = "jwt"
28 | def packageOrg = "ballerina"
29 | def tomlVersion = stripBallerinaExtensionVersion("${project.version}")
30 | def ballerinaTomlFile = new File("$project.projectDir/Ballerina.toml")
31 | def ballerinaTomlFilePlaceHolder = new File("${project.rootDir}/build-config/resources/Ballerina.toml")
32 | def compilerPluginTomlFilePlaceHolder = new File("${project.rootDir}/build-config/resources/CompilerPlugin.toml")
33 | def compilerPluginTomlFile = new File("$project.projectDir/CompilerPlugin.toml")
34 |
35 | def stripBallerinaExtensionVersion(String extVersion) {
36 | if (extVersion.matches(project.ext.timestampedVersionRegex)) {
37 | def splitVersion = extVersion.split('-')
38 | if (splitVersion.length > 3) {
39 | def strippedValues = splitVersion[0..-4]
40 | return strippedValues.join('-')
41 | } else {
42 | return extVersion
43 | }
44 | } else {
45 | return extVersion.replace("${project.ext.snapshotVersion}", "")
46 | }
47 | }
48 |
49 | ballerina {
50 | packageOrganization = packageOrg
51 | module = packageName
52 | langVersion = ballerinaLangVersion
53 | }
54 |
55 | tasks.register('updateTomlFiles') {
56 | doLast {
57 | def newBallerinaToml = ballerinaTomlFilePlaceHolder.text.replace("@project.version@", project.version)
58 | def newCompilerPluginToml = compilerPluginTomlFilePlaceHolder.text.replace("@project.version@", project.version)
59 | newBallerinaToml = newBallerinaToml.replace("@toml.version@", tomlVersion)
60 | ballerinaTomlFile.text = newBallerinaToml
61 | compilerPluginTomlFile.text = newCompilerPluginToml
62 | }
63 | }
64 |
65 | tasks.register('commitTomlFiles') {
66 | doLast {
67 | project.exec {
68 | ignoreExitValue true
69 | if (Os.isFamily(Os.FAMILY_WINDOWS)) {
70 | commandLine 'cmd', '/c', "git commit -m \"[Automated] Update the native jar versions\" Ballerina.toml Dependencies.toml CompilerPlugin.toml"
71 | } else {
72 | commandLine 'sh', '-c', "git commit -m '[Automated] Update the native jar versions' Ballerina.toml Dependencies.toml CompilerPlugin.toml"
73 | }
74 | }
75 | }
76 | }
77 |
78 | publishing {
79 | publications {
80 | maven(MavenPublication) {
81 | artifact source: createArtifactZip, extension: 'zip'
82 | }
83 | }
84 | repositories {
85 | maven {
86 | name = "GitHubPackages"
87 | url = uri("https://maven.pkg.github.com/ballerina-platform/module-${packageOrg}-${packageName}")
88 | credentials {
89 | username = System.getenv("publishUser")
90 | password = System.getenv("publishPAT")
91 | }
92 | }
93 | }
94 | }
95 |
96 | tasks.register('startBallerinaSTS') {
97 | doLast {
98 | // This check is added to prevent starting the server in Windows OS, since the Docker image does not support
99 | // for Windows OS.
100 | if (!Os.isFamily(Os.FAMILY_WINDOWS)) {
101 | def stdOut = new ByteArrayOutputStream()
102 | exec {
103 | commandLine 'sh', '-c', "docker ps --filter name=ballerina-sts"
104 | standardOutput = stdOut
105 | }
106 | if (!stdOut.toString().contains("ballerina-sts")) {
107 | println "Starting Ballerina STS."
108 | exec {
109 | commandLine 'sh', '-c', "docker run --rm -d -p 9445:9445 -p 9444:9444 --name ballerina-sts ldclakmal/ballerina-sts:latest"
110 | standardOutput = stdOut
111 | }
112 | println stdOut.toString()
113 | println "Waiting 10s until the Ballerina STS get initiated."
114 | sleep(15 * 1000)
115 | } else {
116 | println "Ballerina STS is already started."
117 | }
118 | }
119 | }
120 | }
121 | startBallerinaSTS.onlyIf { !project.gradle.startParameter.excludedTaskNames.contains('test') }
122 |
123 | tasks.register('stopBallerinaSTS') {
124 | doLast {
125 | // This check is added to prevent trying to stop the server in Windows OS, since the Docker image not started
126 | // in Windows OS.
127 | if (!Os.isFamily(Os.FAMILY_WINDOWS)) {
128 | def stdOut = new ByteArrayOutputStream()
129 | exec {
130 | commandLine 'sh', '-c', "docker ps --filter name=ballerina-sts"
131 | standardOutput = stdOut
132 | }
133 | if (stdOut.toString().contains("ballerina-sts")) {
134 | println "Stopping Ballerina STS."
135 | exec {
136 | commandLine 'sh', '-c', "docker stop ballerina-sts"
137 | standardOutput = stdOut
138 | }
139 | println stdOut.toString()
140 | println "Waiting 15s until the Ballerina STS get stopped."
141 | sleep(15 * 1000)
142 | } else {
143 | println "Ballerina STS is not started."
144 | }
145 | }
146 | }
147 | }
148 | stopBallerinaSTS.onlyIf { !project.gradle.startParameter.excludedTaskNames.contains('test') }
149 |
150 | updateTomlFiles.dependsOn copyStdlibs
151 |
152 |
153 | test.finalizedBy stopBallerinaSTS
154 | test.dependsOn startBallerinaSTS
155 | test.dependsOn ":${packageName}-native:build"
156 | test.dependsOn ":${packageName}-compiler-plugin:build"
157 |
158 | build.dependsOn ":${packageName}-compiler-plugin:build"
159 | build.dependsOn "generatePomFileForMavenPublication"
160 | build.finalizedBy stopBallerinaSTS
161 | build.dependsOn startBallerinaSTS
162 | build.dependsOn ":${packageName}-native:build"
163 |
164 | publishToMavenLocal.dependsOn build
165 | publish.dependsOn build
166 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Ballerina JWT Library
2 | ===================
3 |
4 | [](https://github.com/ballerina-platform/module-ballerina-jwt/actions/workflows/build-timestamped-master.yml)
5 | [](https://codecov.io/gh/ballerina-platform/module-ballerina-jwt)
6 | [](https://github.com/ballerina-platform/module-ballerina-jwt/actions/workflows/trivy-scan.yml)
7 | [](https://github.com/ballerina-platform/module-ballerina-jwt/actions/workflows/build-with-bal-test-graalvm.yml)
8 | [](https://github.com/ballerina-platform/module-ballerina-jwt/commits/master)
9 | [](https://github.com/ballerina-platform/ballerina-standard-library/labels/module%2Fjwt)
10 |
11 | This library provides a framework for authentication/authorization with JWTs and generation/validation of JWTs as specified in the [RFC 7519](https://datatracker.ietf.org/doc/html/rfc7519), [RFC 7515](https://datatracker.ietf.org/doc/html/rfc7515), and [RFC 7517](https://datatracker.ietf.org/doc/html/rfc7517).
12 |
13 | JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is used as the payload of a JSON Web Signature (JWS) structure or as the plaintext of a JSON Web Encryption (JWE) structure enabling the claims to be signed digitally or protecting the integrity with a Message Authentication Code(MAC) and/or encrypted.
14 |
15 | The Ballerina `jwt` library facilitates auth providers that are to be used by the clients and listeners of different protocol connectors. Also, it provides the APIs for issuing a self-signed JWT and validating a JWT.
16 |
17 | ### Listener JWT Auth provider
18 |
19 | Represents the listener JWT Auth provider, which is used to authenticate the provided credentials (JWT) against the provided JWT validator configurations.
20 |
21 | ### Client JWT Auth provider
22 |
23 | Represents the client JWT Auth provider, which is used to authenticate with an external endpoint by issuing a self-signed JWT against the provided JWT issuer configurations.
24 |
25 | ### JWT issuer
26 |
27 | A self-signed JWT can be issued with the provided configurations using this API as follows:
28 |
29 | ```ballerina
30 | jwt:IssuerConfig issuerConfig = {
31 | username: "ballerina",
32 | issuer: "wso2",
33 | audience: "vEwzbcasJVQm1jVYHUHCjhxZ4tYa",
34 | expTime: 3600,
35 | signatureConfig: {
36 | config: {
37 | keyFile: "/path/to/private.key"
38 | }
39 | }
40 | };
41 |
42 | string jwt = check jwt:issue(issuerConfig);
43 | ```
44 |
45 | ### JWT validator
46 |
47 | A JWT can be validated with the provided configurations using the API as follows:
48 |
49 | ```ballerina
50 | string jwt = "eyJ0eXAiOiJKV1QiLA0KI[...omitted for brevity...]mB92K27uhbwW1gFWFOEjXk";
51 |
52 | jwt:ValidatorConfig validatorConfig = {
53 | issuer: "wso2",
54 | audience: "vEwzbcasJVQm1jVYHUHCjhxZ4tYa",
55 | clockSkew: 60,
56 | signatureConfig: {
57 | certFile: "/path/to/public.crt"
58 | }
59 | };
60 |
61 | jwt:Payload result = check jwt:validate(jwt, validatorConfig);
62 | ```
63 |
64 | ## Issues and projects
65 |
66 | Issues and Projects tabs are disabled for this repository as this is part of the Ballerina Standard Library. To report bugs, request new features, start new discussions, view project boards, etc., go to the [Ballerina Standard Library parent repository](https://github.com/ballerina-platform/ballerina-standard-library).
67 |
68 | This repository only contains the source code for the module.
69 |
70 | ## Build from the source
71 |
72 | ### Set up the prerequisites
73 |
74 | 1. Download and install Java SE Development Kit (JDK) version 21 (from one of the following locations).
75 |
76 | * [Oracle](https://www.oracle.com/java/technologies/downloads/)
77 |
78 | * [OpenJDK](https://adoptium.net)
79 |
80 | > **Note:** Set the `JAVA_HOME` environment variable to the path name of the directory into which you installed JDK.
81 |
82 | 2. Export your GitHub Personal Access Token (PAT) with the `read package` permission as follows:
83 |
84 | ```
85 | export packageUser=
86 | export packagePAT=
87 | ```
88 |
89 | 3. Download and install [Docker](https://www.docker.com/).
90 |
91 | ### Build the source
92 |
93 | Execute the commands below to build from the source.
94 |
95 | 1. To build the package:
96 | ```
97 | ./gradlew clean build
98 | ```
99 | 2. To run the tests:
100 | ```
101 | ./gradlew clean test
102 | ```
103 |
104 | 3. To run a group of tests
105 | ```
106 | ./gradlew clean test -Pgroups=
107 | ```
108 |
109 | 4. To build the without the tests:
110 | ```
111 | ./gradlew clean build -x test
112 | ```
113 |
114 | 5. To debug package implementation:
115 | ```
116 | ./gradlew clean build -Pdebug=
117 | ```
118 |
119 | 6. To debug with Ballerina language:
120 | ```
121 | ./gradlew clean build -PbalJavaDebug=
122 | ```
123 |
124 | 7. Publish the generated artifacts to the local Ballerina central repository:
125 | ```
126 | ./gradlew clean build -PpublishToLocalCentral=true
127 | ```
128 |
129 | 8. Publish the generated artifacts to the Ballerina central repository:
130 | ```
131 | ./gradlew clean build -PpublishToCentral=true
132 | ```
133 |
134 | ## Contribute to Ballerina
135 |
136 | As an open source project, Ballerina welcomes contributions from the community.
137 |
138 | For more information, go to the [contribution guidelines](https://github.com/ballerina-platform/ballerina-lang/blob/master/CONTRIBUTING.md).
139 |
140 | ## Code of conduct
141 |
142 | All contributors are encouraged to read the [Ballerina Code of Conduct](https://ballerina.io/code-of-conduct).
143 |
144 | ## Useful links
145 |
146 | * For more information go to the [`jwt` library](https://lib.ballerina.io/ballerina/jwt/latest).
147 | * For example demonstrations of the usage, go to [Ballerina By Examples](https://ballerina.io/learn/by-example/).
148 | * Chat live with us via our [Discord server](https://discord.gg/ballerinalang).
149 | * Post all technical questions on Stack Overflow with the [#ballerina](https://stackoverflow.com/questions/tagged/ballerina) tag.
150 |
--------------------------------------------------------------------------------
/compiler-plugin-tests/src/test/java/io/ballerina/stdlib/jwt/compiler/staticcodeanalyzer/StaticCodeAnalyzerTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2025, WSO2 LLC. (http://www.wso2.org)
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 | package io.ballerina.stdlib.jwt.compiler.staticcodeanalyzer;
20 |
21 | import com.fasterxml.jackson.databind.JsonNode;
22 | import com.fasterxml.jackson.databind.ObjectMapper;
23 | import com.fasterxml.jackson.databind.SerializationFeature;
24 | import io.ballerina.projects.Project;
25 | import io.ballerina.projects.ProjectEnvironmentBuilder;
26 | import io.ballerina.projects.directory.BuildProject;
27 | import io.ballerina.projects.environment.Environment;
28 | import io.ballerina.projects.environment.EnvironmentBuilder;
29 | import io.ballerina.scan.Issue;
30 | import io.ballerina.scan.Rule;
31 | import io.ballerina.scan.Source;
32 | import io.ballerina.scan.test.Assertions;
33 | import io.ballerina.scan.test.TestOptions;
34 | import io.ballerina.scan.test.TestRunner;
35 | import org.testng.Assert;
36 | import org.testng.annotations.Test;
37 |
38 | import java.io.ByteArrayOutputStream;
39 | import java.io.IOException;
40 | import java.io.PrintStream;
41 | import java.nio.file.Files;
42 | import java.nio.file.Path;
43 | import java.nio.file.Paths;
44 | import java.util.Arrays;
45 | import java.util.List;
46 | import java.util.Locale;
47 | import java.util.stream.Collectors;
48 |
49 | import static io.ballerina.scan.RuleKind.VULNERABILITY;
50 | import static io.ballerina.stdlib.jwt.compiler.staticcodeanalyzer.JwtRule.AVOID_WEAK_CIPHER_ALGORITHMS;
51 | import static java.nio.charset.StandardCharsets.UTF_8;
52 |
53 | public class StaticCodeAnalyzerTest {
54 | private static final Path RESOURCE_PACKAGES_DIRECTORY = Paths
55 | .get("src", "test", "resources", "static_code_analyzer", "ballerina_packages").toAbsolutePath();
56 | private static final Path EXPECTED_OUTPUT_DIRECTORY = Paths
57 | .get("src", "test", "resources", "static_code_analyzer", "expected_output").toAbsolutePath();
58 | private static final Path JSON_RULES_FILE_PATH = Paths
59 | .get("../", "compiler-plugin", "src", "main", "resources", "rules.json").toAbsolutePath();
60 | private static final Path DISTRIBUTION_PATH = Paths.get("../", "target", "ballerina-runtime");
61 | private static final String MODULE_BALLERINA_JWT = "module-ballerina-jwt";
62 |
63 | @Test
64 | public void validateRulesJson() throws IOException {
65 | String expectedRules = "[" + Arrays.stream(JwtRule.values())
66 | .map(JwtRule::toString).collect(Collectors.joining(",")) + "]";
67 | String actualRules = Files.readString(JSON_RULES_FILE_PATH);
68 | assertJsonEqual(actualRules, expectedRules);
69 | }
70 |
71 | @Test
72 | public void testStaticCodeRulesWithAPI() throws IOException {
73 | ByteArrayOutputStream console = new ByteArrayOutputStream();
74 | PrintStream printStream = new PrintStream(console, true, UTF_8);
75 |
76 | for (JwtRule rule : JwtRule.values()) {
77 | testIndividualRule(rule, console, printStream);
78 | }
79 | }
80 |
81 | private void testIndividualRule(JwtRule rule, ByteArrayOutputStream console, PrintStream printStream)
82 | throws IOException {
83 | String targetPackageName = "rule" + rule.getId();
84 | Path targetPackagePath = RESOURCE_PACKAGES_DIRECTORY.resolve(targetPackageName);
85 |
86 | TestRunner testRunner = setupTestRunner(targetPackagePath, printStream);
87 | testRunner.performScan();
88 |
89 | validateRules(testRunner.getRules());
90 | validateIssues(rule, testRunner.getIssues());
91 | validateOutput(console, targetPackageName);
92 |
93 | console.reset();
94 | }
95 |
96 | private TestRunner setupTestRunner(Path targetPackagePath, PrintStream printStream) {
97 | Project project = BuildProject.load(getEnvironmentBuilder(), targetPackagePath);
98 | TestOptions options = TestOptions.builder(project).setOutputStream(printStream).build();
99 | return new TestRunner(options);
100 | }
101 |
102 | private void validateRules(List rules) {
103 | Assertions.assertRule(
104 | rules,
105 | "ballerina/jwt:1",
106 | AVOID_WEAK_CIPHER_ALGORITHMS.getDescription(),
107 | VULNERABILITY);
108 | }
109 |
110 | private void validateIssues(JwtRule rule, List issues) {
111 | switch (rule) {
112 | case AVOID_WEAK_CIPHER_ALGORITHMS:
113 | Assert.assertEquals(issues.size(), 10);
114 | Assertions.assertIssue(issues, 0, "ballerina/jwt:1", "function_named_arg_capture_pattern.bal",
115 | 27, 27, Source.BUILT_IN);
116 | Assertions.assertIssue(issues, 1, "ballerina/jwt:1", "function_named_arg_list_pattern.bal",
117 | 29, 29, Source.BUILT_IN);
118 | Assertions.assertIssue(issues, 2, "ballerina/jwt:1", "function_pos_arg_capture_pattern.bal",
119 | 27, 27, Source.BUILT_IN);
120 | Assertions.assertIssue(issues, 3, "ballerina/jwt:1", "function_pos_arg_list_pattern.bal",
121 | 29, 29, Source.BUILT_IN);
122 | Assertions.assertIssue(issues, 4, "ballerina/jwt:1", "inline_named_arg.bal",
123 | 19, 25, Source.BUILT_IN);
124 | Assertions.assertIssue(issues, 5, "ballerina/jwt:1", "inline_pos_arg.bal",
125 | 19, 25, Source.BUILT_IN);
126 | Assertions.assertIssue(issues, 6, "ballerina/jwt:1", "module_named_arg_capture_pattern.bal",
127 | 27, 27, Source.BUILT_IN);
128 | Assertions.assertIssue(issues, 7, "ballerina/jwt:1", "module_named_arg_list_pattern.bal",
129 | 29, 29, Source.BUILT_IN);
130 | Assertions.assertIssue(issues, 8, "ballerina/jwt:1", "module_pos_arg_capture_pattern.bal",
131 | 27, 27, Source.BUILT_IN);
132 | Assertions.assertIssue(issues, 9, "ballerina/jwt:1", "module_pos_arg_list_pattern.bal",
133 | 29, 29, Source.BUILT_IN);
134 | break;
135 | default:
136 | Assert.fail("Unhandled rule in validateIssues: " + rule);
137 | break;
138 | }
139 | }
140 |
141 | private void validateOutput(ByteArrayOutputStream console, String targetPackageName) throws IOException {
142 | String output = console.toString(UTF_8);
143 | String jsonOutput = extractJson(output);
144 | String expectedOutput = Files.readString(EXPECTED_OUTPUT_DIRECTORY.resolve(targetPackageName + ".json"));
145 | assertJsonEqual(jsonOutput, expectedOutput);
146 | }
147 |
148 | private static ProjectEnvironmentBuilder getEnvironmentBuilder() {
149 | Environment environment = EnvironmentBuilder.getBuilder().setBallerinaHome(DISTRIBUTION_PATH).build();
150 | return ProjectEnvironmentBuilder.getBuilder(environment);
151 | }
152 |
153 | private String extractJson(String consoleOutput) {
154 | int startIndex = consoleOutput.indexOf("[");
155 | int endIndex = consoleOutput.lastIndexOf("]");
156 | if (startIndex == -1 || endIndex == -1) {
157 | return "";
158 | }
159 | return consoleOutput.substring(startIndex, endIndex + 1);
160 | }
161 |
162 | private void assertJsonEqual(String actual, String expected) {
163 | Assert.assertEquals(normalizeString(actual), normalizeString(expected));
164 | }
165 |
166 | private static String normalizeString(String json) {
167 | try {
168 | ObjectMapper mapper = new ObjectMapper().configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
169 | JsonNode node = mapper.readTree(json);
170 | String normalizedJson = mapper.writeValueAsString(node)
171 | .replaceAll(":\".*" + MODULE_BALLERINA_JWT, ":\"" + MODULE_BALLERINA_JWT);
172 | return isWindows() ? normalizedJson.replace("/", "\\\\") : normalizedJson;
173 | } catch (Exception ignore) {
174 | return json;
175 | }
176 | }
177 |
178 | private static boolean isWindows() {
179 | return System.getProperty("os.name").toLowerCase(Locale.ENGLISH).startsWith("windows");
180 | }
181 | }
182 |
--------------------------------------------------------------------------------
/ballerina/tests/test_utils.bal:
--------------------------------------------------------------------------------
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 | import ballerina/test;
18 |
19 | const string KEYSTORE_PATH = "tests/resources/keystore/ballerinaKeystore.p12";
20 | const string TRUSTSTORE_PATH = "tests/resources/keystore/ballerinaTruststore.p12";
21 | const string PRIVATE_KEY_PATH = "tests/resources/key/private.key";
22 | const string ENCRYPTED_PRIVATE_KEY_PATH = "tests/resources/key/encryptedPrivate.key";
23 | const string PUBLIC_CERT_PATH = "tests/resources/cert/public.crt";
24 | const string INVALID_PUBLIC_CERT_PATH = "tests/resources/cert/invalidPublic.crt";
25 |
26 | // {
27 | // "alg": "RS256",
28 | // "typ": "JWT",
29 | // "kid": "5a0b754-895f-4279-8843-b745e11a57e9"
30 | // }
31 | // {
32 | // "iss": "wso2",
33 | // "sub": "John",
34 | // "aud": [
35 | // "ballerina",
36 | // "ballerinaSamples"
37 | // ],
38 | // "jti": "JlbmMiOiJBMTI4Q0JDLUhTMjU2In",
39 | // "exp": 1935400394,
40 | // "nbf": 1620040394,
41 | // "iat": 1620040394,
42 | // "scp": "hello"
43 | // }
44 | const string JWT1 = "eyJhbGciOiJSUzI1NiIsICJ0eXAiOiJKV1QiLCAia2lkIjoiNWEwYjc1NC04OTVmLTQyNzktODg0My1iNzQ1ZTExYTU3ZTk" +
45 | "ifQ.eyJpc3MiOiJ3c28yIiwgInN1YiI6IkpvaG4iLCAiYXVkIjpbImJhbGxlcmluYSIsICJiYWxsZXJpbmFTYW1wbGVzIl0" +
46 | "sICJqdGkiOiJKbGJtTWlPaUpCTVRJNFEwSkRMVWhUTWpVMkluIiwgImV4cCI6MTkzNTQwMDM5NCwgIm5iZiI6MTYyMDA0MD" +
47 | "M5NCwgImlhdCI6MTYyMDA0MDM5NCwgInNjcCI6ImhlbGxvIn0.I9XAfgOkIRor-PTshCzikw92N6jNNPmwXsUTr0OI6bMmG" +
48 | "oEoHw0Uo1g3zOfgKOFfIN0bVqUs9gcg05biojIqFmMErrfG4h1DIIym4PLXWzQ-JWPNnMFYSAC5C84MvBPU5kYMnNbVSTsp" +
49 | "SbQXocY0FHe2_GvhdwHDviRPMS3RnkJxRVORD9BF4DLJuQJdEJUbT_iYSTCd7ay88oCEgm7KGTDKy66-JqC7FAppc7mj7Lk" +
50 | "N48T26BW0aC5wN2LJkYql2H3ONewHOTuEFyH6cZl7dfm66hZiryqMK1BIMwecMscUqKof1h8cHWZ4BDeccCJ5vWNe0SHTrx" +
51 | "3AWPcXnRd0Vw";
52 |
53 | // {
54 | // "alg": "RS256",
55 | // "typ": "JWT",
56 | // "kid": "NTAxZmMxNDMyZDg3MTU1ZGM0MzEzODJhZWI4NDNlZDU1OGFkNjFiMQ"
57 | // }
58 | // {
59 | // "sub": "admin",
60 | // "iss": "ballerina",
61 | // "exp": 1907665746,
62 | // "jti": "100078234ba23",
63 | // "aud": [
64 | // "vEwzbcasJVQm1jVYHUHCjhxZ4tYa"
65 | // ]
66 | // }
67 | const string JWT2 = "eyJhbGciOiJSUzI1NiIsICJ0eXAiOiJKV1QiLCAia2lkIjoiTlRBeFptTXhORE15WkRnM01UVTFaR00wTXpFek9ESmhaV0k" +
68 | "0TkRObFpEVTFPR0ZrTmpGaU1RIn0.eyJzdWIiOiJhZG1pbiIsICJpc3MiOiJiYWxsZXJpbmEiLCAiZXhwIjoxOTA3NjY1Nz" +
69 | "Q2LCAianRpIjoiMTAwMDc4MjM0YmEyMyIsICJhdWQiOlsidkV3emJjYXNKVlFtMWpWWUhVSENqaHhaNHRZYSJdfQ.E8E7VO" +
70 | "18V6MG7Ns87Y314Dqg8RYOMe0WWYlSYFhSv0mHkJQ8bSSyBJzFG0Se_7UsTWFBwzIALw6wUiP7UGraosilf8k6HGJWbTjWt" +
71 | "LXfniJXx5NczikzciG8ADddksm-0AMi5uPsgAQdg7FNaH9f4vAL6SPMEYp2gN6GDnWTH7M1vnknwjOwTbQpGrPu_w2V1tbs" +
72 | "BwSzof3Fk_cYrntu8D_pfsBu3eqFiJZD7AXUq8EYbgIxpSwvdi6_Rvw2_TAi46drouxXK2Jglz_HvheUVCERT15Y8JNJONJ" +
73 | "PJ52MsN6t297hyFV9AmyNPzwHxxmi753TclbapDqDnVPI1tpc-Q";
74 |
75 | // {
76 | // "alg": "RS384",
77 | // "typ": "JWT"
78 | // }
79 | // {
80 | // "iss": "wso2",
81 | // "sub": "John",
82 | // "aud": "ballerina",
83 | // "exp": 1935402506,
84 | // "nbf": 1620042506,
85 | // "iat": 1620042506
86 | // }
87 | const string JWT3 = "eyJhbGciOiJSUzM4NCIsICJ0eXAiOiJKV1QifQ.eyJpc3MiOiJ3c28yIiwgInN1YiI6IkpvaG4iLCAiYXVkIjoiYmFsbGVy" +
88 | "aW5hIiwgImV4cCI6MTkzNTQwMjU4NCwgIm5iZiI6MTYyMDA0MjU4NCwgImlhdCI6MTYyMDA0MjU4NH0.f9HjtIeprPxeYj_" +
89 | "_00pUf8TSS_mlNNvzoY8V8Agg27D4YquxVIj5QwbKjSZ7sdLKC_jlVEwyX0fp_YGcSSfoE-s3T_1wY2e36vxzm35CJG8Lcs" +
90 | "EHwjtMrilJ-CicHJKsz0QsPSJJTDJe490tmPMukh-z1Urm779gYnJroUzDcgEvnrsiLsJwTl7M_VmS56B-iXk7IFoId_6gX" +
91 | "kq3uA9upmyzV6C5C257W_ApMw8icRR8HS19w0NAu5ws_sxkoM6H3SlFqidZgZ0UvTXnvLaQgBaV0RZX8ctzWOqj601vpVqh" +
92 | "qGUvTNGFnpd5ZugLKJ1XXs66ZWdfTkYi2NH_-8cK8Q";
93 |
94 | // {
95 | // "alg": "RS512",
96 | // "typ": "JWT"
97 | // }
98 | // {
99 | // "iss": "wso2",
100 | // "sub": "John",
101 | // "aud": "ballerina",
102 | // "exp": 1935402506,
103 | // "nbf": 1620042506,
104 | // "iat": 1620042506
105 | // }
106 | const string JWT4 = "eyJhbGciOiJSUzUxMiIsICJ0eXAiOiJKV1QifQ.eyJpc3MiOiJ3c28yIiwgInN1YiI6IkpvaG4iLCAiYXVkIjoiYmFsbGVy" +
107 | "aW5hIiwgImV4cCI6MTkzNTQwMjUwNiwgIm5iZiI6MTYyMDA0MjUwNiwgImlhdCI6MTYyMDA0MjUwNn0.R6SobPWHg4z8vY4" +
108 | "OV8MRNocIbQV3tHrgD9MzJeuifofsCRMLAhjhKtldShxA9BnRegmawV6Hqn0dBHgrEW69ydx-frE3k8-u9LufH82Lb5JKb5" +
109 | "ZUm5Zme5PVru628py_e1TGqKyDjMLRwEZUYYxIMV5nmDO6705XDH2sxRSgGBXkJxMGoycnj1UYRLvU7q315js6DKvXY7Yfa" +
110 | "VvO0_xTlFs4381lTXRjkK2G1XMjZQQZK7Px4qSBLqvr9uVPHbezlVKwQs4b1jIgwsE4Fx-bjti6tWCV4NhcU4WhoYB8pYkv" +
111 | "f4WrBpKhcaZQeAiCUA6bUsqSkewvDwtjL9mUs0OkCw";
112 |
113 | // {
114 | // "alg": "RS256",
115 | // "typ": "JWT",
116 | // "kid": "5a0b754-895f-4279-8843-b745e11a57e9"
117 | // }
118 | // {
119 | // "iss": "wso2",
120 | // "sub": "John",
121 | // "aud": [
122 | // "ballerina",
123 | // "ballerinaSamples"
124 | // ],
125 | // "jti": "JlbmMiOiJBMTI4Q0JDLUhTMjU2In",
126 | // "exp": 1940845451,
127 | // "nbf": 1625485451,
128 | // "iat": 1625485451,
129 | // "scp": "hello"
130 | // }
131 | const string JWT5 = "eyJhbGciOiJSUzI1NiIsICJ0eXAiOiJKV1QiLCAia2lkIjoiNWEwYjc1NC04OTVmLTQyNzktODg0My1iNzQ1ZTExYTU3ZTk" +
132 | "ifQ.eyJpc3MiOiJ3c28yIiwgInN1YiI6IkpvaG4iLCAiYXVkIjpbImJhbGxlcmluYSIsICJiYWxsZXJpbmFTYW1wbGVzIl0" +
133 | "sICJqdGkiOiJKbGJtTWlPaUpCTVRJNFEwSkRMVWhUTWpVMkluIiwgImV4cCI6MTk0MDg0NTQ1MSwgIm5iZiI6MTYyNTQ4NT" +
134 | "Q1MSwgImlhdCI6MTYyNTQ4NTQ1MSwgInNjcCI6ImhlbGxvIn0.G0c9t9AE7BmYhKCNY4DsYmypk4XDQ-lNqpENYUouugWXn" +
135 | "t3-d2rpLHxnXNqcIqPBWRV6QuxO-0jcp6LjkjO2khgZ5jMVNFtlyUN4cQ9UEHfwiPAjSlkwT7sAEHPUd8S8wp714eWtkdjo" +
136 | "ysgpcdEE3VJi1OgI1SeVDiN6l7jkt-xxhMsbHGYIeTc1lTLgwNtCJaNJKHvi0uJu5x9YfUznett8Dw465DbADhBLMoSBYAT" +
137 | "t4flzCBsTGWC7XZaFnwT4mUlX7WpTOgv1Nsq5GVLszvsnzs6BE__Mvr4zl5pdChVbkMXX3US6fYguK268XKjzgtpMVxUpL3" +
138 | "CrzwQpIRyI-Q";
139 |
140 | // {
141 | // "alg": "HS256",
142 | // "typ": "JWT"
143 | // }
144 | // {
145 | // "iss": "wso2",
146 | // "sub": "John",
147 | // "aud": [
148 | // "ballerina",
149 | // "ballerinaSamples"
150 | // ],
151 | // "exp": 1943255429,
152 | // "nbf": 1627895429,
153 | // "iat": 1627895429
154 | // }
155 | const string JWT6 = "eyJhbGciOiJIUzI1NiIsICJ0eXAiOiJKV1QifQ.eyJpc3MiOiJ3c28yIiwgInN1YiI6IkpvaG4iLCAiYXVkIjpbImJhbGxl" +
156 | "cmluYSIsICJiYWxsZXJpbmFTYW1wbGVzIl0sICJleHAiOjE5NDMyNTU0MjksICJuYmYiOjE2Mjc4OTU0MjksICJpYXQiOjE" +
157 | "2Mjc4OTU0Mjl9.BqFvZtKFj4KiVGkSkbXAcG4mpmSnGM0f60GYMw7dj4k";
158 |
159 | // {
160 | // "alg": "HS384",
161 | // "typ": "JWT"
162 | // }
163 | // {
164 | // "iss": "wso2",
165 | // "sub": "John",
166 | // "aud": [
167 | // "ballerina",
168 | // "ballerinaSamples"
169 | // ],
170 | // "exp": 1943257494,
171 | // "nbf": 1627897494,
172 | // "iat": 1627897494
173 | // }
174 | const string JWT7 = "eyJhbGciOiJIUzM4NCIsICJ0eXAiOiJKV1QifQ.eyJpc3MiOiJ3c28yIiwgInN1YiI6IkpvaG4iLCAiYXVkIjpbImJhbGxl" +
175 | "cmluYSIsICJiYWxsZXJpbmFTYW1wbGVzIl0sICJleHAiOjE5NDMyNTc0OTQsICJuYmYiOjE2Mjc4OTc0OTQsICJpYXQiOjE" +
176 | "2Mjc4OTc0OTR9.gwyn7kbaX-AQi0SQQmPoKfazehSsr7XUTnxewKny2qcOOVJrIqlLVyCoyacFlPel";
177 |
178 | // {
179 | // "alg": "HS512",
180 | // "typ": "JWT"
181 | // }
182 | // {
183 | // "iss": "wso2",
184 | // "sub": "John",
185 | // "aud": [
186 | // "ballerina",
187 | // "ballerinaSamples"
188 | // ],
189 | // "exp": 1944016504,
190 | // "nbf": 1628656504,
191 | // "iat": 1628656504
192 | // }
193 | const string JWT8 = "eyJhbGciOiJIUzUxMiIsICJ0eXAiOiJKV1QifQ.eyJpc3MiOiJ3c28yIiwgInN1YiI6IkpvaG4iLCAiYXVkIjpbImJhbGxl" +
194 | "cmluYSIsICJiYWxsZXJpbmFTYW1wbGVzIl0sICJleHAiOjE5NDQwMTY1MDQsICJuYmYiOjE2Mjg2NTY1MDQsICJpYXQiOjE" +
195 | "2Mjg2NTY1MDR9.pXPpwlNyqvNdkmDhYYwhKGArcZXbMz9sqXpv-I05Nox65Q0tMDkzSIK-jpkrp-yag737v4GckS8MuZuym" +
196 | "ee43Q";
197 |
198 | // Builds the complete error message by evaluating all the inner causes and asserts the inclusion.
199 | isolated function assertContains(error err, string text) {
200 | string message = err.message();
201 | error? cause = err.cause();
202 | while cause is error {
203 | message += " " + cause.message();
204 | cause = cause.cause();
205 | }
206 | test:assertTrue(message.includes(text));
207 | }
208 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015-2021 the original authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | #
21 | # Gradle start up script for POSIX generated by Gradle.
22 | #
23 | # Important for running:
24 | #
25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
26 | # noncompliant, but you have some other compliant shell such as ksh or
27 | # bash, then to run this script, type that shell name before the whole
28 | # command line, like:
29 | #
30 | # ksh Gradle
31 | #
32 | # Busybox and similar reduced shells will NOT work, because this script
33 | # requires all of these POSIX shell features:
34 | # * functions;
35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
37 | # * compound commands having a testable exit status, especially «case»;
38 | # * various built-in commands including «command», «set», and «ulimit».
39 | #
40 | # Important for patching:
41 | #
42 | # (2) This script targets any POSIX shell, so it avoids extensions provided
43 | # by Bash, Ksh, etc; in particular arrays are avoided.
44 | #
45 | # The "traditional" practice of packing multiple parameters into a
46 | # space-separated string is a well documented source of bugs and security
47 | # problems, so this is (mostly) avoided, by progressively accumulating
48 | # options in "$@", and eventually passing that to Java.
49 | #
50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
52 | # see the in-line comments for details.
53 | #
54 | # There are tweaks for specific operating systems such as AIX, CygWin,
55 | # Darwin, MinGW, and NonStop.
56 | #
57 | # (3) This script is generated from the Groovy template
58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
59 | # within the Gradle project.
60 | #
61 | # You can find Gradle at https://github.com/gradle/gradle/.
62 | #
63 | ##############################################################################
64 |
65 | # Attempt to set APP_HOME
66 |
67 | # Resolve links: $0 may be a link
68 | app_path=$0
69 |
70 | # Need this for daisy-chained symlinks.
71 | while
72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
73 | [ -h "$app_path" ]
74 | do
75 | ls=$( ls -ld "$app_path" )
76 | link=${ls#*' -> '}
77 | case $link in #(
78 | /*) app_path=$link ;; #(
79 | *) app_path=$APP_HOME$link ;;
80 | esac
81 | done
82 |
83 | # This is normally unused
84 | # shellcheck disable=SC2034
85 | APP_BASE_NAME=${0##*/}
86 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
87 |
88 | # Use the maximum available, or set MAX_FD != -1 to use that value.
89 | MAX_FD=maximum
90 |
91 | warn () {
92 | echo "$*"
93 | } >&2
94 |
95 | die () {
96 | echo
97 | echo "$*"
98 | echo
99 | exit 1
100 | } >&2
101 |
102 | # OS specific support (must be 'true' or 'false').
103 | cygwin=false
104 | msys=false
105 | darwin=false
106 | nonstop=false
107 | case "$( uname )" in #(
108 | CYGWIN* ) cygwin=true ;; #(
109 | Darwin* ) darwin=true ;; #(
110 | MSYS* | MINGW* ) msys=true ;; #(
111 | NONSTOP* ) nonstop=true ;;
112 | esac
113 |
114 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
115 |
116 |
117 | # Determine the Java command to use to start the JVM.
118 | if [ -n "$JAVA_HOME" ] ; then
119 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
120 | # IBM's JDK on AIX uses strange locations for the executables
121 | JAVACMD=$JAVA_HOME/jre/sh/java
122 | else
123 | JAVACMD=$JAVA_HOME/bin/java
124 | fi
125 | if [ ! -x "$JAVACMD" ] ; then
126 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
127 |
128 | Please set the JAVA_HOME variable in your environment to match the
129 | location of your Java installation."
130 | fi
131 | else
132 | JAVACMD=java
133 | if ! command -v java >/dev/null 2>&1
134 | then
135 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
136 |
137 | Please set the JAVA_HOME variable in your environment to match the
138 | location of your Java installation."
139 | fi
140 | fi
141 |
142 | # Increase the maximum file descriptors if we can.
143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
144 | case $MAX_FD in #(
145 | max*)
146 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
147 | # shellcheck disable=SC3045
148 | MAX_FD=$( ulimit -H -n ) ||
149 | warn "Could not query maximum file descriptor limit"
150 | esac
151 | case $MAX_FD in #(
152 | '' | soft) :;; #(
153 | *)
154 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
155 | # shellcheck disable=SC3045
156 | ulimit -n "$MAX_FD" ||
157 | warn "Could not set maximum file descriptor limit to $MAX_FD"
158 | esac
159 | fi
160 |
161 | # Collect all arguments for the java command, stacking in reverse order:
162 | # * args from the command line
163 | # * the main class name
164 | # * -classpath
165 | # * -D...appname settings
166 | # * --module-path (only if needed)
167 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
168 |
169 | # For Cygwin or MSYS, switch paths to Windows format before running java
170 | if "$cygwin" || "$msys" ; then
171 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
172 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
173 |
174 | JAVACMD=$( cygpath --unix "$JAVACMD" )
175 |
176 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
177 | for arg do
178 | if
179 | case $arg in #(
180 | -*) false ;; # don't mess with options #(
181 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
182 | [ -e "$t" ] ;; #(
183 | *) false ;;
184 | esac
185 | then
186 | arg=$( cygpath --path --ignore --mixed "$arg" )
187 | fi
188 | # Roll the args list around exactly as many times as the number of
189 | # args, so each arg winds up back in the position where it started, but
190 | # possibly modified.
191 | #
192 | # NB: a `for` loop captures its iteration list before it begins, so
193 | # changing the positional parameters here affects neither the number of
194 | # iterations, nor the values presented in `arg`.
195 | shift # remove old arg
196 | set -- "$@" "$arg" # push replacement arg
197 | done
198 | fi
199 |
200 |
201 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
202 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
203 |
204 | # Collect all arguments for the java command;
205 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
206 | # shell script including quotes and variable substitutions, so put them in
207 | # double quotes to make sure that they get re-expanded; and
208 | # * put everything else in single quotes, so that it's not re-expanded.
209 |
210 | set -- \
211 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
212 | -classpath "$CLASSPATH" \
213 | org.gradle.wrapper.GradleWrapperMain \
214 | "$@"
215 |
216 | # Stop when "xargs" is not available.
217 | if ! command -v xargs >/dev/null 2>&1
218 | then
219 | die "xargs is not available"
220 | fi
221 |
222 | # Use "xargs" to parse quoted args.
223 | #
224 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
225 | #
226 | # In Bash we could simply go:
227 | #
228 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
229 | # set -- "${ARGS[@]}" "$@"
230 | #
231 | # but POSIX shell has neither arrays nor command substitution, so instead we
232 | # post-process each arg (as a line of input to sed) to backslash-escape any
233 | # character that might be a shell metacharacter, then use eval to reverse
234 | # that process (while maintaining the separation between arguments), and wrap
235 | # the whole thing up as a single "set" statement.
236 | #
237 | # This will of course break if any of these variables contains a newline or
238 | # an unmatched quote.
239 | #
240 |
241 | eval "set -- $(
242 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
243 | xargs -n1 |
244 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
245 | tr '\n' ' '
246 | )" '"$@"'
247 |
248 | exec "$JAVACMD" "$@"
249 |
--------------------------------------------------------------------------------
/ballerina/jwt_issuer.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 | import ballerina/crypto;
18 | import ballerina/time;
19 |
20 | # Represents JWT issuer configurations.
21 | #
22 | # + issuer - JWT issuer, which is mapped to the `iss`
23 | # + username - JWT username, which is mapped to the `sub`
24 | # + audience - JWT audience, which is mapped to the `aud`
25 | # + jwtId - JWT ID, which is mapped to the `jti`
26 | # + keyId - JWT key ID, which is mapped the `kid`
27 | # + customClaims - Map of custom claims
28 | # + expTime - Expiry time in seconds
29 | # + signatureConfig - JWT signature configurations
30 | public type IssuerConfig record {|
31 | string issuer?;
32 | string username?;
33 | string|string[] audience?;
34 | string jwtId?;
35 | string keyId?;
36 | map customClaims?;
37 | decimal expTime = 300;
38 | IssuerSignatureConfig signatureConfig?;
39 | |};
40 |
41 | # Represents JWT signature configurations.
42 | #
43 | # + algorithm - Cryptographic signing algorithm for JWS
44 | # + config - KeyStore configurations, private key configurations, `crypto:PrivateKey` or shared key configurations
45 | public type IssuerSignatureConfig record {|
46 | SigningAlgorithm algorithm = RS256;
47 | record {|
48 | crypto:KeyStore keyStore;
49 | string keyAlias;
50 | string keyPassword;
51 | |} | record {|
52 | string keyFile;
53 | string keyPassword?;
54 | |} | crypto:PrivateKey | string config?;
55 | |};
56 |
57 | # Issues a JWT based on the provided configurations. JWT will be signed (JWS) if `crypto:KeyStore` information is
58 | # provided in the `jwt:KeyStoreConfig` and the `jwt:SigningAlgorithm` is not `jwt:NONE`.
59 | # ```ballerina
60 | # string jwt = check jwt:issue(issuerConfig);
61 | # ```
62 | #
63 | # + issuerConfig - JWT issuer configurations
64 | # + return - JWT as a `string` or else a `jwt:Error` if an error occurred
65 | public isolated function issue(IssuerConfig issuerConfig) returns string|Error {
66 | Header header = prepareHeader(issuerConfig);
67 | Payload payload = preparePayload(issuerConfig);
68 | string headerString = check buildHeaderString(header);
69 | string payloadString = check buildPayloadString(payload);
70 | string jwtAssertion = headerString + "." + payloadString;
71 |
72 | IssuerSignatureConfig? issuerSignatureConfig = issuerConfig?.signatureConfig;
73 | if issuerSignatureConfig is () {
74 | return jwtAssertion;
75 | }
76 | IssuerSignatureConfig signatureConfig = issuerSignatureConfig;
77 | SigningAlgorithm algorithm = signatureConfig.algorithm;
78 | if algorithm is NONE {
79 | return jwtAssertion;
80 | }
81 | var config = signatureConfig?.config;
82 | if config is () {
83 | return prepareError("Signing JWT requires keystore information or private key information.");
84 | } else if config is string {
85 | return hmacJwtAssertion(jwtAssertion, algorithm, config);
86 | } else if config?.keyStore is crypto:KeyStore {
87 | crypto:KeyStore keyStore = config?.keyStore;
88 | string keyAlias = config?.keyAlias;
89 | string keyPassword = config?.keyPassword;
90 | crypto:PrivateKey|crypto:Error privateKey = crypto:decodeRsaPrivateKeyFromKeyStore(keyStore, keyAlias, keyPassword);
91 | if privateKey is crypto:PrivateKey {
92 | return signJwtAssertion(jwtAssertion, algorithm, privateKey);
93 | } else {
94 | return prepareError("Failed to decode private key.", privateKey);
95 | }
96 | } else if config is crypto:PrivateKey {
97 | return signJwtAssertion(jwtAssertion, algorithm, config);
98 | } else {
99 | string keyFile = config?.keyFile;
100 | string? keyPassword = config?.keyPassword;
101 | crypto:PrivateKey|crypto:Error privateKey = crypto:decodeRsaPrivateKeyFromKeyFile(keyFile, keyPassword);
102 | if privateKey is crypto:PrivateKey {
103 | return signJwtAssertion(jwtAssertion, algorithm, privateKey);
104 | } else {
105 | return prepareError("Failed to decode private key.", privateKey);
106 | }
107 | }
108 | }
109 |
110 | isolated function signJwtAssertion(string jwtAssertion, SigningAlgorithm alg, crypto:PrivateKey privateKey)
111 | returns string|Error {
112 | match alg {
113 | RS256 => {
114 | byte[]|crypto:Error signature = crypto:signRsaSha256(jwtAssertion.toBytes(), privateKey);
115 | if signature is byte[] {
116 | return (jwtAssertion + "." + encodeBase64Url(signature));
117 | } else {
118 | return prepareError("RSA private key signing failed for SHA256 algorithm.", signature);
119 | }
120 | }
121 | RS384 => {
122 | byte[]|crypto:Error signature = crypto:signRsaSha384(jwtAssertion.toBytes(), privateKey);
123 | if signature is byte[] {
124 | return (jwtAssertion + "." + encodeBase64Url(signature));
125 | } else {
126 | return prepareError("RSA private key signing failed for SHA384 algorithm.", signature);
127 | }
128 | }
129 | RS512 => {
130 | byte[]|crypto:Error signature = crypto:signRsaSha512(jwtAssertion.toBytes(), privateKey);
131 | if signature is byte[] {
132 | return (jwtAssertion + "." + encodeBase64Url(signature));
133 | } else {
134 | return prepareError("RSA private key signing failed for SHA512 algorithm.", signature);
135 | }
136 | }
137 | _ => {
138 | return prepareError("Unsupported signing algorithm '" + alg.toString() + "'.");
139 | }
140 | }
141 | }
142 |
143 | isolated function hmacJwtAssertion(string jwtAssertion, SigningAlgorithm alg, string secret)
144 | returns string|Error {
145 | match alg {
146 | HS256 => {
147 | byte[]|crypto:Error signature = crypto:hmacSha256(jwtAssertion.toBytes(), secret.toBytes());
148 | if signature is byte[] {
149 | return (jwtAssertion + "." + encodeBase64Url(signature));
150 | } else {
151 | return prepareError("HMAC secret key signing failed for SHA256 algorithm.", signature);
152 | }
153 | }
154 | HS384 => {
155 | byte[]|crypto:Error signature = crypto:hmacSha384(jwtAssertion.toBytes(), secret.toBytes());
156 | if signature is byte[] {
157 | return (jwtAssertion + "." + encodeBase64Url(signature));
158 | } else {
159 | return prepareError("HMAC secret key signing failed for SHA384 algorithm.", signature);
160 | }
161 | }
162 | HS512 => {
163 | byte[]|crypto:Error signature = crypto:hmacSha512(jwtAssertion.toBytes(), secret.toBytes());
164 | if signature is byte[] {
165 | return (jwtAssertion + "." + encodeBase64Url(signature));
166 | } else {
167 | return prepareError("HMAC secret key signing failed for SHA512 algorithm.", signature);
168 | }
169 | }
170 | _ => {
171 | return prepareError("Unsupported signing algorithm '" + alg.toString() + "'.");
172 | }
173 | }
174 | }
175 |
176 | isolated function prepareHeader(IssuerConfig issuerConfig) returns Header {
177 | Header header = { alg: NONE, typ: "JWT" };
178 | IssuerSignatureConfig? issuerSignatureConfig = issuerConfig?.signatureConfig;
179 | if issuerSignatureConfig is IssuerSignatureConfig {
180 | header.alg = issuerSignatureConfig.algorithm;
181 | }
182 | string? kid = issuerConfig?.keyId;
183 | if kid is string {
184 | header.kid = kid;
185 | }
186 | return header;
187 | }
188 |
189 | isolated function preparePayload(IssuerConfig issuerConfig) returns Payload {
190 | [int, decimal] currentTime = time:utcNow();
191 | Payload payload = {
192 | exp: currentTime[0] + issuerConfig.expTime,
193 | iat: currentTime[0],
194 | nbf: currentTime[0]
195 | };
196 |
197 | string? iss = issuerConfig?.issuer;
198 | if iss is string {
199 | payload.iss = iss;
200 | }
201 | string? sub = issuerConfig?.username;
202 | if sub is string {
203 | payload.sub = sub;
204 | }
205 | string|string[]? aud = issuerConfig?.audience;
206 | if aud is string || aud is string[] {
207 | payload.aud = aud;
208 | }
209 | string? jti = issuerConfig?.jwtId;
210 | if jti is string {
211 | payload.jti = jti;
212 | }
213 |
214 | map? customClaims = issuerConfig?.customClaims;
215 | if customClaims is map {
216 | foreach string key in customClaims.keys() {
217 | payload[key] = customClaims[key];
218 | }
219 | }
220 | return payload;
221 | }
222 |
223 | isolated function buildHeaderString(Header header) returns string|Error {
224 | if !validateMandatoryHeaderFields(header) {
225 | return prepareError("Mandatory field signing algorithm (alg) is empty.");
226 | }
227 | return encodeBase64Url(header.toJsonString().toBytes());
228 | }
229 |
230 | isolated function buildPayloadString(Payload payload) returns string|Error {
231 | return encodeBase64Url(payload.toJsonString().toBytes());
232 | }
233 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------