diff --git a/src/content/docs/api-shield/security/jwt-validation/api.mdx b/src/content/docs/api-shield/security/jwt-validation/api.mdx index b29d7535714..65ae25dd874 100644 --- a/src/content/docs/api-shield/security/jwt-validation/api.mdx +++ b/src/content/docs/api-shield/security/jwt-validation/api.mdx @@ -10,10 +10,9 @@ sidebar: head: - tag: title content: Configure JWT validation via the API - --- -import { GlossaryTooltip } from "~/components" +import { GlossaryTooltip } from "~/components"; Use the Cloudflare API to configure [JWT validation](/api-shield/security/jwt-validation/), which requires token configurations and token validation rules. @@ -48,7 +47,7 @@ Refer to the [Ruleset Engine documentation](/ruleset-engine/rules-language/field ### Credentials -API Shield supports credentials of type `RS256`, `RS384`, `RS512`, `PS256`, `PS384`, `PS512`, `ES256`, and `ES384`. RSA keys must be at least 2048-bit. Each JSON web key must have a “KID” which must be present in the JWT's header as well to allow API Shield to match them. +API Shield supports credentials of type `RS256`, `RS384`, `RS512`, `PS256`, `PS384`, `PS512`, `ES256`, and `ES384`. RSA keys must be at least 2048-bit. Each JSON web key must have a “KID” which must be present in the JWT's header as well to allow API Shield to match them. We allow up to 4 different keys in order to aid in key rollover. @@ -62,26 +61,26 @@ The example below shows a JSON object with all of the information necessary to c ```json title="Example" { - "title": "Production JWT configuration", - "description": "This configuration checks the JWT in the authorization header or cookie.", - "token_sources": [ - "http.request.headers[\"authorization\"][0]", - "http.request.cookies[\"Authorization\"][0]" - ], - "token_type": "jwt", - "credentials": { - "keys": [ - { - "kty": "EC", - "use": "sig", - "crv": "P-256", - "kid": "93UrzmNu1mqXs5cZcvCPkTlMHB2Jya30vSTkiBb0vhU", - "x": "QG3VFVwUX4IatQvBy7sqBvvmticCZ-eX5-nbtGKBOfI", - "y": "A3PXCshn7XcG7Ivvd2K_DerW4LHAlIVKdqhrUnczTD0", - "alg": "ES256" - } - ] - } + "title": "Production JWT configuration", + "description": "This configuration checks the JWT in the authorization header or cookie.", + "token_sources": [ + "http.request.headers[\"authorization\"][0]", + "http.request.cookies[\"Authorization\"][0]" + ], + "token_type": "jwt", + "credentials": { + "keys": [ + { + "kty": "EC", + "use": "sig", + "crv": "P-256", + "kid": "93UrzmNu1mqXs5cZcvCPkTlMHB2Jya30vSTkiBb0vhU", + "x": "QG3VFVwUX4IatQvBy7sqBvvmticCZ-eX5-nbtGKBOfI", + "y": "A3PXCshn7XcG7Ivvd2K_DerW4LHAlIVKdqhrUnczTD0", + "alg": "ES256" + } + ] + } } ``` @@ -120,33 +119,33 @@ The response will be in a Cloudflare `v4` response envelope and the result conta ```json title="Example response" { - "result": { - "id": "d5902294-00c3-4aed-b517-57e752e9cd58", - "token_type": "JWT", - "title": "Production JWT configuration", - "description": "This configuration checks the JWT in the authorization header or cookie.", - "token_sources": [ - "http.request.headers[\"authorization\"][0]", - "http.request.cookies[\"Authorization\"][0]" - ], - "credentials": { - "keys": [ - { - "x": "QG3VFVwUX4IatQvBy7sqBvvmticCZ-eX5-nbtGKBOfI", - "y": "A3PXCshn7XcG7Ivvd2K_DerW4LHAlIVKdqhrUnczTD0", - "alg": "ES256", - "crv": "P-256", - "kid": "93UrzmNu1mqXs5cZcvCPkTlMHB2Jya30vSTkiBb0vhU", - "kty": "EC" - } - ] - }, - "created_at": "2023-11-08T16:45:17.236841Z", - "last_updated": "2023-11-08T16:45:17.236841Z" - }, - "success": true, - "errors": [], - "messages": [] + "result": { + "id": "d5902294-00c3-4aed-b517-57e752e9cd58", + "token_type": "JWT", + "title": "Production JWT configuration", + "description": "This configuration checks the JWT in the authorization header or cookie.", + "token_sources": [ + "http.request.headers[\"authorization\"][0]", + "http.request.cookies[\"Authorization\"][0]" + ], + "credentials": { + "keys": [ + { + "x": "QG3VFVwUX4IatQvBy7sqBvvmticCZ-eX5-nbtGKBOfI", + "y": "A3PXCshn7XcG7Ivvd2K_DerW4LHAlIVKdqhrUnczTD0", + "alg": "ES256", + "crv": "P-256", + "kid": "93UrzmNu1mqXs5cZcvCPkTlMHB2Jya30vSTkiBb0vhU", + "kty": "EC" + } + ] + }, + "created_at": "2023-11-08T16:45:17.236841Z", + "last_updated": "2023-11-08T16:45:17.236841Z" + }, + "success": true, + "errors": [], + "messages": [] } ``` @@ -156,12 +155,12 @@ Token validation rules allow you to enforce a security policy using existing tok Token validation rules can be configured using the Cloudflare API or [dashboard](/api-shield/security/jwt-validation/#add-a-jwt-validation-rule). -|
Field name
| Description | Example | Notes | -| ----------------------------------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `title` | A human-readable name allowing you to quickly identify it. | JWT validation on `v1` and `v2.example.com` | Limited to 50 characters. | -| `description` | A human-readable description that gives more details than `title` and helps to document it. | Log requests without a valid `authorization` header. | Limited to 500 characters. | -| `action` | The Firewall Action taken on requests that do not meet `expression`. | `log` | Possible: `log` or `block` | -| `enabled` | Enable or disable the rule. | `true` | Possible: `true` or `false` | +|
Field name
| Description | Example | Notes | +| ----------------------------------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `title` | A human-readable name allowing you to quickly identify it. | JWT validation on `v1` and `v2.example.com` | Limited to 50 characters. | +| `description` | A human-readable description that gives more details than `title` and helps to document it. | Log requests without a valid `authorization` header. | Limited to 500 characters. | +| `action` | The Firewall Action taken on requests that do not meet `expression`. | `log` | Possible: `log` or `block` | +| `enabled` | Enable or disable the rule. | `true` | Possible: `true` or `false` | | `expression` | The rule's security policy. | `is_jwt_valid ("00170473-ec24-410e-968a-9905cf0a7d03")` | Make sure to escape any quotes when creating rules using the Cloudflare API.
Refer to [Define a security policy](#define-a-security-policy) below. | | `selector` | Configure what operations are covered by this rule. | | Refer to [Applying a rule to operations](#apply-a-rule-to-operations) below. | @@ -197,10 +196,8 @@ Operators such as `or`, `and`, `eq`, and more are usable in expressions in the s The following functions can be used to interact with JWT Tokens on a request: -|
Function
| Description | Notes | -| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | -| `is_jwt_valid(token_configuration_id String) bool` | `True` if the request has a valid token according to the token configuration with the ID `token_configuration_id`. | `token_configuration_id` must be the ID of an existing token configuration. This will return `false` if the token is missing from the request. | -| `is_jwt_present(token_configuration_id String) bool` | `True` if the request has a token as configured in the token configuration with the ID `token_configuration_id`. | `token_configuration_id` must be the ID of an existing token configuration. | +- [`is_jwt_valid(token_configuration_id)`](/ruleset-engine/rules-language/functions/#is_jwt_valid) — Returns true if the request has a valid token according to the token configuration with the ID `token_configuration_id`. +- [`is_jwt_present(token_configuration_id)`](/ruleset-engine/rules-language/functions/#is_jwt_present) — Returns true if the request has a token as configured in the token configuration with the ID `token_configuration_id`. ### Common use cases @@ -220,7 +217,7 @@ It can be combined with a `block` action in the token validation rule to block r #### Require at least one of two possible tokens -The `is_jwt_valid("51231d16-01f1-48e3-93f8-91c99e81288e") or is_jwt_valid("fddfc39e-3686-4683-ab23-bf917da6bb43")` expressions will trigger an action if a request does not have at least one valid token. +The `is_jwt_valid("51231d16-01f1-48e3-93f8-91c99e81288e") or is_jwt_valid("fddfc39e-3686-4683-ab23-bf917da6bb43")` expressions will trigger an action if a request does not have at least one valid token. This can occur if you need to split JWKs into multiple token configurations. @@ -243,22 +240,19 @@ For example, the following selector will apply a rule to all operations in `v1.e ```json title="Selector example" { - "include": [ - { - "host": [ - "v1.example.com", - "v2.example.com" - ] - } - ], - "exclude": [ - { - "operation_ids": [ - "f9c5615e-fe15-48ce-bec6-cfc1946f1bec", // POST v1.example.com/login - "56828eae-035a-4396-ba07-51c66d680a04" // POST v2.example.com/login - ] - } - ] + "include": [ + { + "host": ["v1.example.com", "v2.example.com"] + } + ], + "exclude": [ + { + "operation_ids": [ + "f9c5615e-fe15-48ce-bec6-cfc1946f1bec", // POST v1.example.com/login + "56828eae-035a-4396-ba07-51c66d680a04" // POST v2.example.com/login + ] + } + ] } ``` @@ -296,89 +290,86 @@ The `state` field can be `ignored`, `excluded`, or `included`. Included operatio ```json title="Result" { - "result": { - "operations": [ - { - "operation_id": "ed15fcb6-5a73-41cd-91af-8c61e5bb1cdb", - "method": "GET", - "host": "example.com", - "endpoint": "/api/accounts/{var1}", - "last_updated": "2023-05-24T14:54:34.806506Z", - "state": "ignored" - }, - { - "operation_id": "e7a582cd-3cfb-4061-ab5b-722e6e42f545", - "method": "GET", - "host": "v1.example.com", - "endpoint": "/api/accounts/{var1}", - "last_updated": "2023-05-24T14:54:34.806506Z", - "state": "included" - }, - { - "operation_id": "ddd5df5a-795c-40ce-b38c-38e9d7ef9ae8", - "method": "GET", - "host": "v2.example.com", - "endpoint": "/api/accounts/{var1}", - "last_updated": "2023-05-24T14:54:34.806506Z", - "state": "included" - }, - { - "operation_id": "4d20befb-0120-45d5-9b29-5835fd41b44e", - "method": "GET", - "host": "v3.example.com", - "endpoint": "/api/accounts/{var1}", - "last_updated": "2023-05-24T14:54:34.806506Z", - "state": "ignored" - }, - { - "operation_id": "f9c5615e-fe15-48ce-bec6-cfc1946f1bec", - "method": "POST", - "host": "v1.example.com", - "endpoint": "/login", - "last_updated": "2023-05-24T14:54:34.806506Z", - "state": "excluded" - }, - { - "operation_id": "56828eae-035a-4396-ba07-51c66d680a04", - "method": "POST", - "host": "v2.example.com", - "endpoint": "/login", - "last_updated": "2023-05-24T14:54:34.806506Z", - "state": "excluded" - }, - { - "operation_id": "cf86874c-8d0c-4337-ae14-4e2459b541ac", - "method": "GET", - "host": "v3.example.com", - "endpoint": "login", - "last_updated": "2023-05-24T14:54:34.806506Z", - "state": "ignored" - } - ], - "total": 7, - "included": 2, - "excluded": 2, - "ignored": 3, - "selected_hosts": [ - "v1.example.com", - "v2.example.com" - ], - "available_hosts": [ - "example.com", - "v1.example.com", - "v1.example.com", - "v3.example.com" - ] - }, - "success": true, - "errors": [], - "messages": [], - "result_info": { - "page": 1, - "per_page": 20, - "count": 20, - "total_count": 1631 - } + "result": { + "operations": [ + { + "operation_id": "ed15fcb6-5a73-41cd-91af-8c61e5bb1cdb", + "method": "GET", + "host": "example.com", + "endpoint": "/api/accounts/{var1}", + "last_updated": "2023-05-24T14:54:34.806506Z", + "state": "ignored" + }, + { + "operation_id": "e7a582cd-3cfb-4061-ab5b-722e6e42f545", + "method": "GET", + "host": "v1.example.com", + "endpoint": "/api/accounts/{var1}", + "last_updated": "2023-05-24T14:54:34.806506Z", + "state": "included" + }, + { + "operation_id": "ddd5df5a-795c-40ce-b38c-38e9d7ef9ae8", + "method": "GET", + "host": "v2.example.com", + "endpoint": "/api/accounts/{var1}", + "last_updated": "2023-05-24T14:54:34.806506Z", + "state": "included" + }, + { + "operation_id": "4d20befb-0120-45d5-9b29-5835fd41b44e", + "method": "GET", + "host": "v3.example.com", + "endpoint": "/api/accounts/{var1}", + "last_updated": "2023-05-24T14:54:34.806506Z", + "state": "ignored" + }, + { + "operation_id": "f9c5615e-fe15-48ce-bec6-cfc1946f1bec", + "method": "POST", + "host": "v1.example.com", + "endpoint": "/login", + "last_updated": "2023-05-24T14:54:34.806506Z", + "state": "excluded" + }, + { + "operation_id": "56828eae-035a-4396-ba07-51c66d680a04", + "method": "POST", + "host": "v2.example.com", + "endpoint": "/login", + "last_updated": "2023-05-24T14:54:34.806506Z", + "state": "excluded" + }, + { + "operation_id": "cf86874c-8d0c-4337-ae14-4e2459b541ac", + "method": "GET", + "host": "v3.example.com", + "endpoint": "login", + "last_updated": "2023-05-24T14:54:34.806506Z", + "state": "ignored" + } + ], + "total": 7, + "included": 2, + "excluded": 2, + "ignored": 3, + "selected_hosts": ["v1.example.com", "v2.example.com"], + "available_hosts": [ + "example.com", + "v1.example.com", + "v1.example.com", + "v3.example.com" + ] + }, + "success": true, + "errors": [], + "messages": [], + "result_info": { + "page": 1, + "per_page": 20, + "count": 20, + "total_count": 1631 + } } ``` @@ -403,37 +394,34 @@ Replace any token configurations IDs and operation IDs with the IDs that exist i ```json title="Token Validation Rule JSON example" [ - { - "title": "JWT Validation on v1 and v2.example.com", - "description": "Log requests without a valid authorization header.", - "action": "log", - "enabled": true, - "expression": "is_jwt_valid(\"00170473-ec24-410e-968a-9905cf0a7d03\")", - "selector": { - "include": [ - { - "host": [ - "v1.example.com", - "v2.example.com" - ] - } - ], - "exclude": [ - { - "operation_ids": [ - "f9c5615e-fe15-48ce-bec6-cfc1946f1bec", - "56828eae-035a-4396-ba07-51c66d680a04" - ] - } - ] - } - } + { + "title": "JWT Validation on v1 and v2.example.com", + "description": "Log requests without a valid authorization header.", + "action": "log", + "enabled": true, + "expression": "is_jwt_valid(\"00170473-ec24-410e-968a-9905cf0a7d03\")", + "selector": { + "include": [ + { + "host": ["v1.example.com", "v2.example.com"] + } + ], + "exclude": [ + { + "operation_ids": [ + "f9c5615e-fe15-48ce-bec6-cfc1946f1bec", + "56828eae-035a-4396-ba07-51c66d680a04" + ] + } + ] + } + } ] ``` ## Create a token Validation rule using the Cloudflare API -Use cURL or any other API client tool to send the new configuration to Cloudflare’s API to enable JWT validation. Make sure to replace `{zone_id}` with the relevant zone ID and add your [authentication credentials](/fundamentals/api/get-started/create-token/) header. +Use cURL or any other API client tool to send the new configuration to Cloudflare's API to enable JWT validation. Make sure to replace `{zone_id}` with the relevant zone ID and add your [authentication credentials](/fundamentals/api/get-started/create-token/) header. Replace any token configurations IDs and operation IDs with the IDs that exist in your zone. @@ -475,40 +463,37 @@ The response will be in a Cloudflare `v4` response envelope and the result conta ```json title="Result" { - "result": [ - { - "id": "5ec7c417-6964-4b24-b82c-a23a7ec8f90c", - "title": "JWT Validation on v1 and v2.example.com", - "description": "Log requests without a valid authorization header.", - "action": "log", - "enabled": true, - "expression": "is_jwt_valid(\"00170473-ec24-410e-968a-9905cf0a7d03\")", - "selector": { - "include": [ - { - "host": [ - "v1.example.com", - "v2.example.com" - ] - } - ], - "exclude": [ - { - "operation_ids": [ - "f9c5615e-fe15-48ce-bec6-cfc1946f1bec", - "56828eae-035a-4396-ba07-51c66d680a04" - ] - } - ] - }, - "created_at": "2023-10-18T12:08:09.575388Z", - "last_updated": "2023-10-18T12:08:09.575388Z", - "modified_by": "user@cloudflare.com" - } - ], - "success": true, - "errors": [], - "messages": [] + "result": [ + { + "id": "5ec7c417-6964-4b24-b82c-a23a7ec8f90c", + "title": "JWT Validation on v1 and v2.example.com", + "description": "Log requests without a valid authorization header.", + "action": "log", + "enabled": true, + "expression": "is_jwt_valid(\"00170473-ec24-410e-968a-9905cf0a7d03\")", + "selector": { + "include": [ + { + "host": ["v1.example.com", "v2.example.com"] + } + ], + "exclude": [ + { + "operation_ids": [ + "f9c5615e-fe15-48ce-bec6-cfc1946f1bec", + "56828eae-035a-4396-ba07-51c66d680a04" + ] + } + ] + }, + "created_at": "2023-10-18T12:08:09.575388Z", + "last_updated": "2023-10-18T12:08:09.575388Z", + "modified_by": "user@cloudflare.com" + } + ], + "success": true, + "errors": [], + "messages": [] } ``` diff --git a/src/content/docs/ruleset-engine/rules-language/functions.mdx b/src/content/docs/ruleset-engine/rules-language/functions.mdx index 084e760b84a..5fbd683771f 100644 --- a/src/content/docs/ruleset-engine/rules-language/functions.mdx +++ b/src/content/docs/ruleset-engine/rules-language/functions.mdx @@ -150,7 +150,6 @@ Decodes a Base64-encoded String specified in `source`. For example, with the following HTTP request header: `client_id: MTIzYWJj`, `(any(decode_base64(http.request.headers["client_id"][*])[*] eq "123abc"))` would return `true`. - :::note You can only use the `decode_base64()` function in [Transform Rules](/rules/transform/), [custom rules](/waf/custom-rules/), and [rate limiting rules](/waf/rate-limiting-rules/). ::: @@ -226,6 +225,40 @@ has_value(http.request.headers.names, "X-My-Header") has_value(http.request.headers.names, http.request.uri.args.names[0]) ``` +### `is_jwt_present` + +is_jwt_present(token_configuration_id: ): + +Returns true if the request has a token as configured in the token configuration with the ID `token_configuration_id`. + +`token_configuration_id` must be the ID of an existing [token configuration](/api-shield/security/jwt-validation/api/#token-configurations). + +Example: + +```txt +is_jwt_present("51231d16-01f1-48e3-93f8-91c99e81288e") +``` + +:::note +This function is only available in [API JWT validation rules](/api-shield/security/jwt-validation/). +::: + +### `is_jwt_valid` + +is_jwt_valid(token_configuration_id: ): + +Returns true if the request has a valid token according to the token configuration with the ID `token_configuration_id`. + +`token_configuration_id` must be the ID of an existing [token configuration](/api-shield/security/jwt-validation/api/#token-configurations). The function returns false if the token is missing from the request. + +```txt +is_jwt_valid("51231d16-01f1-48e3-93f8-91c99e81288e") +``` + +:::note +This function is only available in [API JWT validation rules](/api-shield/security/jwt-validation/). +::: + ### `len` len():