Assignment and Equality

  1. # assign variable x to value of field foo.bar.baz in input
  2. x := input.foo.bar.baz
  3. # check if variable x has same value as variable y
  4. x == y
  5. # check if variable x is a set containing "foo" and "bar"
  6. x == {"foo", "bar"}
  7. # OR
  8. {"foo", "bar"} == x

Lookup

Arrays

  1. # lookup value at index 0
  2. val := arr[0]
  3. # check if value at index 0 is "foo"
  4. "foo" == arr[0]
  5. # find all indices i that have value "foo"
  6. "foo" == arr[i]
  7. # lookup last value
  8. val := arr[count(arr)-1]

Objects

  1. # lookup value for key "foo"
  2. val := obj["foo"]
  3. # check if value for key "foo" is "bar"
  4. "bar" == obj["foo"]
  5. # OR
  6. "bar" == obj.foo
  7. # check if key "foo" exists and is not false
  8. obj.foo
  9. # check if key assigned to variable k exists
  10. k := "foo"
  11. obj[k]
  12. # check if path foo.bar.baz exists and is not false
  13. obj.foo.bar.baz
  14. # check if path foo.bar.baz, foo.bar, or foo does not exist or is false
  15. not obj.foo.bar.baz

Sets

  1. # check if "foo" belongs to the set
  2. a_set["foo"]
  3. # check if "foo" DOES NOT belong to the set
  4. not a_set["foo"]
  5. # check if the array ["a", "b", "c"] belongs to the set
  6. a_set[["a", "b", "c"]]
  7. # find all arrays of the form [x, "b", z] in the set
  8. a_set[[x, "b", z]]

Iteration

Arrays

  1. # iterate over indices i
  2. arr[i]
  3. # iterate over values
  4. val := arr[_]
  5. # iterate over index/value pairs
  6. val := arr[i]

Objects

  1. # iterate over keys
  2. obj[key]
  3. # iterate over values
  4. val := obj[_]
  5. # iterate over key/value pairs
  6. val := obj[key]

Sets

  1. # iterate over values
  2. set[val]

Advanced

  1. # nested: find key k whose bar.baz array index i is 7
  2. foo[k].bar.baz[i] == 7
  3. # simultaneous: find keys in objects foo and bar with same value
  4. foo[k1] == bar[k2]
  5. # simultaneous self: find 2 keys in object foo with same value
  6. foo[k1] == foo[k2]; k1 != k2
  7. # multiple conditions: k has same value in both conditions
  8. foo[k].bar.baz[i] == 7; foo[k].qux > 3

For All

  1. # assert no values in set match predicate
  2. count({x | set[x]; f(x)}) == 0
  3. # assert all values in set make function f true
  4. count({x | set[x]; f(x)}) == count(set)
  5. # assert no values in set make function f true (using negation and helper rule)
  6. not any_match
  7. # assert all values in set make function f true (using negation and helper rule)
  8. not any_not_match
  1. any_match {
  2. set[x]
  3. f(x)
  4. }
  5. any_not_match {
  6. set[x]
  7. not f(x)
  8. }

Rules

In the examples below ... represents one or more conditions.

Constants

  1. a = {1, 2, 3}
  2. b = {4, 5, 6}
  3. c = a | b

Conditionals (Boolean)

  1. # p is true if ...
  2. p = true { ...}
  3. # OR
  4. p { ... }

Conditionals

  1. default a = 1
  2. a = 5 { ... }
  3. a = 100 { ... }

Incremental

  1. # a_set will contain values of x and values of y
  2. a_set[x] { ... }
  3. a_set[y] { ... }
  4. # a_map will contain key->value pairs x->y and w->z
  5. a_map[x] = y { ... }
  6. a_map[w] = z { ... }

Ordered (Else)

  1. default a = 1
  2. a = 5 { ... }
  3. else = 10 { ... }

Functions (Boolean)

  1. f(x, y) {
  2. ...
  3. }
  4. # OR
  5. f(x, y) = true {
  6. ...
  7. }

Functions (Conditionals)

  1. f(x) = "A" { x >= 90 }
  2. f(x) = "B" { x >= 80; x < 90 }
  3. f(x) = "C" { x >= 70; x < 80 }

Tests

  1. # define a rule that starts with test_
  2. test_NAME { ... }
  3. # override input.foo value using the 'with' keyword
  4. data.foo.bar.deny with input.foo as {"bar": [1,2,3]}}

Built-in Functions

The built-in functions for the language provide basic operations to manipulate scalar values (e.g. numbers and strings), and aggregate functions that summarize complex types.

Comparison

Built-inDescriptionWasm Support
x == yx is equal to y
x != yx is not equal to y
x < yx is less than y
x <= yx is less than or equal to y
x > yx is greater than y
x >= yx is greater than or equal to y

Numbers

Built-inDescriptionWasm Support
z := x + yz is the sum of x and y
z := x - yz is the difference of x and y
z := x * yz is the product of x and y
z := x / yz is the quotient of x and y
z := x % yz is the remainder from the division of x and y
output := round(x)output is x rounded to the nearest integer
output := ceil(x)output is x rounded up to the nearest integer
output := floor(x)output is x rounded down the nearest integer
output := abs(x)output is the absolute value of x
output := numbers.range(a, b)output is the range of integer numbers between a and b (inclusive). If a == b then output == [a]. If a < b the range is in ascending order. If a > b the range is in descending order.
output := rand.intn(str, n)output is a number in the range [0, abs(n)). If n is 0, then output is 0. For any given (str, n) pair the output will be consistent throughout a query evaluation.SDK-dependent

Aggregates

Built-inDescriptionWasm Support
output := count(collection_or_string)output is the length of the object, array, set, or string provided as input
output := sum(array_or_set)output is the sum of the numbers in array_or_set
output := product(array_or_set)output is the product of the numbers in array_or_set
output := max(array_or_set)output is the maximum value in array_or_set
output := min(array_or_set)output is the minimum value in array_or_set
output := sort(array_or_set)output is the sorted array containing elements from array_or_set.

Arrays

Built-inDescriptionWasm Support
output := array.concat(array, array)output is the result of concatenating the two input arrays together.
output := array.slice(array, startIndex, stopIndex)output is the part of the array from startIndex to stopIndex including the first but excluding the last. If startIndex >= stopIndex then output == []. If both startIndex and stopIndex are less than zero, output == []. Otherwise, startIndex and stopIndex are clamped to 0 and count(array) respectively.

Sets

Built-inDescriptionWasm Support
s3 := s1 & s2s3 is the intersection of s1 and s2.
s3 := s1 | s2s3 is the union of s1 and s2.
s3 := s1 - s2s3 is the difference between s1 and s2, i.e., the elements in s1 that are not in s2
output := intersection(set[set])output is the intersection of the sets in the input set
output := union(set[set])output is the union of the sets in the input set

Objects

Built-inDescriptionWasm Support
value := object.get(object, key, default)value is the value stored by the object at key. If no value is found, default is returned.
output := object.remove(object, keys)output is a new object which is the result of removing the specified keys from object. keys must be either an array, object, or set of keys.
output := object.union(objectA, objectB)output is a new object which is the result of an asymmetric recursive union of two objects where conflicts are resolved by choosing the key from the right-hand object (objectB). For example: object.union({“a”: 1, “b”: 2, “c”: {“d”: 3}}, {“a”: 7, “c”: {“d”: 4, “e”: 5}}) will result in {“a”: 7, “b”: 2, “c”: {“d”: 4, “e”: 5}}
filtered := object.filter(object, keys)filtered is a new object with the remaining data from object with only keys specified in keys which is an array, object, or set of keys. For example: object.filter({“a”: {“b”: “x”, “c”: “y”}, “d”: “z”}, [“a”]) will result in {“a”: {“b”: “x”, “c”: “y”}}).
filtered := json.filter(object, paths)filtered is the remaining data from object with only keys specified in paths which is an array or set of JSON string paths. For example: json.filter({“a”: {“b”: “x”, “c”: “y”}}, [“a/b”]) will result in {“a”: {“b”: “x”}}). Paths are not filtered in-order and are deduplicated before being evaluated.
output := json.remove(object, paths)output is a new object which is the result of removing all keys specified in paths which is an array or set of JSON string paths. For example: json.remove({“a”: {“b”: “x”, “c”: “y”}}, [“a/b”]) will result in {“a”: {“c”: “y”}}. Paths are not removed in-order and are deduplicated before being evaluated.
output := json.patch(object, patches)output is a the object obtained after consecutively applying all JSON Patch operations in the array patches. For example: json.patch({“a”: {“foo”: 1}}, [{“op”: “add”, “path”: “/a/bar”, “value”: 2}]) results in {“a”: {“foo”: 1, “bar”: 2}. The patches are applied atomically: if any of them fails, the result will be undefined.SDK-dependent
  • When keys are provided as an object only the top level keys on the object will be used, values are ignored. For example: object.remove({"a": {"b": {"c": 2}}, "x": 123}, {"a": 1}) == {"x": 123} regardless of the value for key a in the keys object, the following keys object gives the same result object.remove({"a": {"b": {"c": 2}}, "x": 123}, {"a": {"b": {"foo": "bar"}}}) == {"x": 123}.

  • The json string paths may reference into array values by using index numbers. For example with the object {"a": ["x", "y", "z"]} the path a/1 references y. Nested structures are supported as well, for example: {"a": ["x", {"y": {"y1": {"y2": ["foo", "bar"]}}}, "z"]} the path a/1/y1/y2/0 references "foo".

  • The json string paths support ~0, or ~1 characters for ~ and / characters in key names. It does not support - for last index of an array. For example the path /foo~1bar~0 will reference baz in { "foo/bar~": "baz" }.

  • The json string paths may be an array of string path segments rather than a / separated string. For example the path a/b/c can be passed in as ["a", "b", "c"].

Strings

Built-inDescriptionWasm Support
output := concat(delimiter, array_or_set)output is the result of joining together the elements of array_or_set with the string delimiter
contains(string, search)true if string contains search
endswith(string, search)true if string ends with search
output := format_int(number, base)output is string representation of number in the given base
output := indexof(string, search)output is the index inside string where search first occurs, or -1 if search does not exist
output := lower(string)output is string after converting to lower case
output := replace(string, old, new)output is a string representing string with all instances of old replaced by new
output := strings.replace_n(patterns, string)patterns is an object with old, new string key value pairs (e.g. {“old1”: “new1”, “old2”: “new2”, …}). output is a string with all old strings inside patterns replaced by the new strings
output := split(string, delimiter)output is array[string] representing elements of string separated by delimiter
output := sprintf(string, values)output is a string representing string formatted by the values in the array values.SDK-dependent
startswith(string, search)true if string begins with search
output := substring(string, start, length)output is the portion of string from index start and having a length of length. If length is less than zero, length is the remainder of the string. If start is greater than the length of the string, output is empty. It is invalid to pass a negative offset to this function.
output := trim(string, cutset)output is a string representing string with all leading and trailing instances of the characters in cutset removed.
output := trim_left(string, cutset)output is a string representing string with all leading instances of the characters in cutset removed.
output := trim_prefix(string, prefix)output is a string representing string with leading instance of prefix removed. If string doesn’t start with prefix, string is returned unchanged.
output := trim_right(string, cutset)output is a string representing string with all trailing instances of the characters in cutset removed.
output := trim_suffix(string, suffix)output is a string representing string with trailing instance of suffix removed. If string doesn’t end with suffix, string is returned unchanged.
output := trim_space(string)output is a string representing string with all leading and trailing white space removed.
output := upper(string)output is string after converting to upper case

Regex

Built-inDescriptionWasm Support
output := regex.match(pattern, value)output is a boolean that indicates if value matches the regex pattern.
output := regex.is_valid(pattern)output is a boolean that indicates if pattern is a valid regex pattern. The detailed syntax for regex patterns is defined by https://github.com/google/re2/wiki/Syntax.
output := regex.split(pattern, string)output is array[string] representing elements of string separated by patternSDK-dependent
regex.globs_match(glob1, glob2)true if the intersection of regex-style globs glob1 and glob2 matches a non-empty set of non-empty strings. The set of regex symbols is limited for this builtin: only ., , +, [, -, ] and \ are treated as special symbols.SDK-dependent
output := regex.template_match(pattern, string, delimiter_start, delimiter_end)output is true if string matches pattern. pattern is a string containing 0..n regular expressions delimited by delimiter_start and delimiter_end. Example regex.template_match(“urn:foo:{.}”, “urn:foo:bar:baz”, “{“, “}”) returns true.SDK-dependent
output := regex.find_n(pattern, string, number)output is an array[string] with the number of values matching the pattern. A number of -1 means all matches.SDK-dependent
output := regex.find_all_string_submatch_n(pattern, string, number)output is an array[array[string]] with the outer array including a number of matches which match the pattern. A number of -1 means all matches.

Glob

Built-inDescriptionWasm Support
output := glob.match(pattern, delimiters, match)output is true if match can be found in pattern which is separated by delimiters. For valid patterns, check the table below. Argument delimiters is an array of single-characters (e.g. [“.”, “:”]). If delimiters is empty, it defaults to [“.”].
output := glob.quote_meta(pattern)output is the escaped string of pattern. Calling glob.quote_meta(“.github.com”, output) returns \.github.com as output.SDK-dependent

The following table shows examples of how glob.match works:

calloutputDescription
output := glob.match(“.github.com”, [], “api.github.com”)trueA glob with the default [“.”] delimiter.
output := glob.match(“.github.com”, [], “api.cdn.github.com”)falseA glob with the default [“.”] delimiter.
output := glob.match(“:github:com”, [“:”], “api:github:com”)trueA glob with delimiters [“:”].
output := glob.match(“api.*.com”, [], “api.github.com”)trueA super glob.
output := glob.match(“api..com”, [], “api.cdn.github.com”)trueA super glob.
output := glob.match(“?at”, [], “cat”)trueA glob with a single character wildcard.
output := glob.match(“?at”, [], “at”)falseA glob with a single character wildcard.
output := glob.match(“[abc]at”, [], “bat”)trueA glob with character-list matchers.
output := glob.match(“[abc]at”, [], “cat”)trueA glob with character-list matchers.
output := glob.match(“[abc]at”, [], “lat”)falseA glob with character-list matchers.
output := glob.match(“[!abc]at”, [], “cat”)falseA glob with negated character-list matchers.
output := glob.match(“[!abc]at”, [], “lat”)trueA glob with negated character-list matchers.
output := glob.match(“[a-c]at”, [], “cat”)trueA glob with character-range matchers.
output := glob.match(“[a-c]at”, [], “lat”)falseA glob with character-range matchers.
output := glob.match(“[!a-c]at”, [], “cat”)falseA glob with negated character-range matchers.
output := glob.match(“[!a-c]at”, [], “lat”)trueA glob with negated character-range matchers.
output := glob.match(“{cat,bat,[fr]at}”, [], “cat”)trueA glob with pattern-alternatives matchers.
output := glob.match(“{cat,bat,[fr]at}”, [], “bat”)trueA glob with pattern-alternatives matchers.
output := glob.match(“{cat,bat,[fr]at}”, [], “rat”)trueA glob with pattern-alternatives matchers.
output := glob.match(“{cat,bat,[fr]at}”, [], “at”)falseA glob with pattern-alternatives matchers.

Bitwise

Built-inDescriptionWasm Support
z := bits.or(x, y)z is the bitwise or of integers x and y
z := bits.and(x, y)z is the bitwise and of integers x and y
z := bits.negate(x)z is the bitwise negation (flip) of integer x
z := bits.xor(x, y)z is the bitwise exclusive-or of integers x and y
z := bits.lsh(x, s)z is the bitshift of integer x by s bits to the left
z := bits.rsh(x, s)z is the bitshift of integer x by s bits to the right

Conversions

Built-inDescriptionWasm Support
output := to_number(x)output is x converted to a number. null is converted to zero, true and false are converted to one and zero (respectively), string values are interpreted as base 10, and numbers are a no-op. Other types are not supported.

Units

Built-inDescriptionWasm Support
output := units.parse_bytes(x)output is x converted to a number with support for standard byte units (e.g., KB, KiB, etc.) KB, MB, GB, and TB are treated as decimal units and KiB, MiB, GiB, and TiB are treated as binary units. The bytes symbol (b/B) in the unit is optional and omitting it wil give the same result (e.g. Mi and MiB)SDK-dependent

Types

Built-inDescriptionWasm Support
output := is_number(x)output is true if x is a number; otherwise undefined
output := is_string(x)output is true if x is a string; otherwise undefined
output := is_boolean(x)output is true if x is a boolean; otherwise undefined
output := is_array(x)output is true if x is an array; otherwise undefined
output := is_set(x)output is true if x is a set; otherwise undefined
output := is_object(x)output is true if x is an object; otherwise undefined
output := is_null(x)output is true if x is null; otherwise undefined
output := type_name(x)output is the type of x (e.g. “number”, “boolean”, …)

Encoding

Built-inDescriptionWasm Support
output := base64.encode(x)output is x serialized to a base64 encoded string without padding
output := base64.decode(string)output is x deserialized from a base64 encoding string without padding
output := base64url.encode(x)output is x serialized to a base64url encoded string with padding
output := base64url.encode_no_pad(x)output is x serialized to a base64url encoded string without paddingSDK-dependent
output := base64url.decode(string)output is string deserialized from a base64url encoded string with or without padding
output := urlquery.encode(string)output is string serialized to a URL query parameter encoded stringSDK-dependent
output := urlquery.encode_object(object)output is object serialized to a URL query parameter encoded stringSDK-dependent
output := urlquery.decode(string)output is string deserialized from a URL query parameter encoded stringSDK-dependent
output := urlquery.decode_object(string)output is object deserialized from a URL query parameter stringSDK-dependent
output := json.marshal(x)output is x serialized to a JSON string
output := json.unmarshal(string)output is string deserialized to a term from a JSON encoded string
output := json.is_valid(string)output is a boolean that indicated whether string is a valid JSON documentSDK-dependent
output := yaml.marshal(x)output is x serialized to a YAML stringSDK-dependent
output := yaml.unmarshal(string)output is string deserialized to a term from YAML encoded stringSDK-dependent
output := yaml.is_valid(string)output is a boolean that indicated whether string is a valid YAML document that can be decoded by yaml.unmarshalSDK-dependent
output := hex.encode(x)output is x serialized to a hex encoded stringSDK-dependent
output := hex.decode(string)output is a string deserialized from a hex encoded stringSDK-dependent

Token Signing

OPA provides two builtins that implement JSON Web Signature RFC7515 functionality.

io.jwt.encode_sign_raw() takes three JSON Objects (strings) as parameters and returns their JWS Compact Serialization. This builtin should be used by those that want maximum control over the signing and serialization procedure. It is important to remember that StringOrURI values are compared as case-sensitive strings with no transformations or canonicalizations applied. Therefore, line breaks and whitespaces are significant.

io.jwt.encode_sign() takes three Rego Objects as parameters and returns their JWS Compact Serialization. This builtin should be used by those that want to use rego objects for signing during policy evaluation.

Note that with io.jwt.encode_sign the Rego objects are serialized to JSON with standard formatting applied whereas the io.jwt.encode_sign_raw built-in will not affect whitespace of the strings passed in. This will mean that the final encoded token may have different string values, but the decoded and parsed JSON will match.

The following algorithms are supported:

  1. ES256 "ES256" // ECDSA using P-256 and SHA-256
  2. ES384 "ES384" // ECDSA using P-384 and SHA-384
  3. ES512 "ES512" // ECDSA using P-521 and SHA-512
  4. HS256 "HS256" // HMAC using SHA-256
  5. HS384 "HS384" // HMAC using SHA-384
  6. HS512 "HS512" // HMAC using SHA-512
  7. PS256 "PS256" // RSASSA-PSS using SHA256 and MGF1-SHA256
  8. PS384 "PS384" // RSASSA-PSS using SHA384 and MGF1-SHA384
  9. PS512 "PS512" // RSASSA-PSS using SHA512 and MGF1-SHA512
  10. RS256 "RS256" // RSASSA-PKCS-v1.5 using SHA-256
  11. RS384 "RS384" // RSASSA-PKCS-v1.5 using SHA-384
  12. RS512 "RS512" // RSASSA-PKCS-v1.5 using SHA-512
Built-inDescriptionWasm Support
output := io.jwt.encode_sign_raw(headers, payload, key)headers, payload and key as strings that represent the JWS Protected Header, JWS Payload and JSON Web Key (RFC7517) respectively.SDK-dependent
output := io.jwt.encode_sign(headers, payload, key)headers, payload and key are JSON objects that represent the JWS Protected Header, JWS Payload and JSON Web Key (RFC7517) respectively.SDK-dependent

Note that the key’s provided should be base64 encoded (without padding) as per the specification (RFC7517). This differs from the plain text secrets provided with the algorithm specific verify built-ins described below.

Token Signing Examples

  1. package jwt
Symmetric Key (HMAC with SHA-256)
  1. io.jwt.encode_sign({
  2. "typ": "JWT",
  3. "alg": "HS256"
  4. }, {
  5. "iss": "joe",
  6. "exp": 1300819380,
  7. "aud": ["bob", "saul"],
  8. "http://example.com/is_root": true,
  9. "privateParams": {
  10. "private_one": "one",
  11. "private_two": "two"
  12. }
  13. }, {
  14. "kty": "oct",
  15. "k": "AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"
  16. })
  1. "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJhdWQiOiBbImJvYiIsICJzYXVsIl0sICJleHAiOiAxMzAwODE5MzgwLCAiaHR0cDovL2V4YW1wbGUuY29tL2lzX3Jvb3QiOiB0cnVlLCAiaXNzIjogImpvZSIsICJwcml2YXRlUGFyYW1zIjogeyJwcml2YXRlX29uZSI6ICJvbmUiLCAicHJpdmF0ZV90d28iOiAidHdvIn19.M10TcaFADr_JYAx7qJ71wktdyuN4IAnhWvVbgrZ5j_4"
Symmetric Key with empty JSON payload
  1. io.jwt.encode_sign({
  2. "typ": "JWT",
  3. "alg": "HS256"},
  4. {}, {
  5. "kty": "oct",
  6. "k": "AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"
  7. })
  1. "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.e30.Odp4A0Fj6NoKsV4Gyoy1NAmSs6KVZiC15S9VRGZyR20"
RSA Key (RSA Signature with SHA-256)
  1. io.jwt.encode_sign({
  2. "alg": "RS256"
  3. }, {
  4. "iss": "joe",
  5. "exp": 1300819380,
  6. "aud": ["bob", "saul"],
  7. "http://example.com/is_root": true,
  8. "privateParams": {
  9. "private_one": "one",
  10. "private_two": "two"
  11. }
  12. },
  13. {
  14. "kty": "RSA",
  15. "n": "ofgWCuLjybRlzo0tZWJjNiuSfb4p4fAkd_wWJcyQoTbji9k0l8W26mPddxHmfHQp-Vaw-4qPCJrcS2mJPMEzP1Pt0Bm4d4QlL-yRT-SFd2lZS-pCgNMsD1W_YpRPEwOWvG6b32690r2jZ47soMZo9wGzjb_7OMg0LOL-bSf63kpaSHSXndS5z5rexMdbBYUsLA9e-KXBdQOS-UTo7WTBEMa2R2CapHg665xsmtdVMTBQY4uDZlxvb3qCo5ZwKh9kG4LT6_I5IhlJH7aGhyxXFvUK-DWNmoudF8NAco9_h9iaGNj8q2ethFkMLs91kzk2PAcDTW9gb54h4FRWyuXpoQ",
  16. "e": "AQAB",
  17. "d": "Eq5xpGnNCivDflJsRQBXHx1hdR1k6Ulwe2JZD50LpXyWPEAeP88vLNO97IjlA7_GQ5sLKMgvfTeXZx9SE-7YwVol2NXOoAJe46sui395IW_GO-pWJ1O0BkTGoVEn2bKVRUCgu-GjBVaYLU6f3l9kJfFNS3E0QbVdxzubSu3Mkqzjkn439X0M_V51gfpRLI9JYanrC4D4qAdGcopV_0ZHHzQlBjudU2QvXt4ehNYTCBr6XCLQUShb1juUO1ZdiYoFaFQT5Tw8bGUl_x_jTj3ccPDVZFD9pIuhLhBOneufuBiB4cS98l2SR_RQyGWSeWjnczT0QU91p1DhOVRuOopznQ",
  18. "p": "4BzEEOtIpmVdVEZNCqS7baC4crd0pqnRH_5IB3jw3bcxGn6QLvnEtfdUdiYrqBdss1l58BQ3KhooKeQTa9AB0Hw_Py5PJdTJNPY8cQn7ouZ2KKDcmnPGBY5t7yLc1QlQ5xHdwW1VhvKn-nXqhJTBgIPgtldC-KDV5z-y2XDwGUc",
  19. "q": "uQPEfgmVtjL0Uyyx88GZFF1fOunH3-7cepKmtH4pxhtCoHqpWmT8YAmZxaewHgHAjLYsp1ZSe7zFYHj7C6ul7TjeLQeZD_YwD66t62wDmpe_HlB-TnBA-njbglfIsRLtXlnDzQkv5dTltRJ11BKBBypeeF6689rjcJIDEz9RWdc",
  20. "dp": "BwKfV3Akq5_MFZDFZCnW-wzl-CCo83WoZvnLQwCTeDv8uzluRSnm71I3QCLdhrqE2e9YkxvuxdBfpT_PI7Yz-FOKnu1R6HsJeDCjn12Sk3vmAktV2zb34MCdy7cpdTh_YVr7tss2u6vneTwrA86rZtu5Mbr1C1XsmvkxHQAdYo0",
  21. "dq": "h_96-mK1R_7glhsum81dZxjTnYynPbZpHziZjeeHcXYsXaaMwkOlODsWa7I9xXDoRwbKgB719rrmI2oKr6N3Do9U0ajaHF-NKJnwgjMd2w9cjz3_-kyNlxAr2v4IKhGNpmM5iIgOS1VZnOZ68m6_pbLBSp3nssTdlqvd0tIiTHU",
  22. "qi": "IYd7DHOhrWvxkwPQsRM2tOgrjbcrfvtQJipd-DlcxyVuuM9sQLdgjVk2oy26F0EmpScGLq2MowX7fhd_QJQ3ydy5cY7YIBi87w93IKLEdfnbJtoOPLUW0ITrJReOgo1cq9SbsxYawBgfp_gh6A5603k2-ZQwVK0JKSHuLFkuQ3U"
  23. })
  1. "eyJhbGciOiAiUlMyNTYifQ.eyJhdWQiOiBbImJvYiIsICJzYXVsIl0sICJleHAiOiAxMzAwODE5MzgwLCAiaHR0cDovL2V4YW1wbGUuY29tL2lzX3Jvb3QiOiB0cnVlLCAiaXNzIjogImpvZSIsICJwcml2YXRlUGFyYW1zIjogeyJwcml2YXRlX29uZSI6ICJvbmUiLCAicHJpdmF0ZV90d28iOiAidHdvIn19.ITpfhDICCeVV__1nHRN2CvUFni0yyYESvhNlt4ET0yiySMzJ5iySGynrsM3kgzAv7mVmx5uEtSCs_xPHyLVfVnADKmDFtkZfuvJ8jHfcOe8TUqR1f7j1Zf_kDkdqJAsuGuqkJoFJ3S_gxWcZNwtDXV56O3k_7Mq03Ixuuxtip2oF0X3fB7QtUzjzB8mWPTJDFG2TtLLOYCcobPHmn36aAgesHMzJZj8U8sRLmqPXsIc-Lo_btt8gIUc9zZSgRiy7NOSHxw5mYcIMlKl93qvLXu7AaAcVLvzlIOCGWEnFpGGcRFgSOLnShQX6hDylWavKLQG-VOUJKmtXH99KBK-OYQ"
Raw Token Signing

If you need to generate the signature for a serialized token you an use the io.jwt.encode_sign_raw built-in function which accepts JSON serialized string parameters.

  1. io.jwt.encode_sign_raw(
  2. `{"typ":"JWT","alg":"HS256"}`,
  3. `{"iss":"joe","exp":1300819380,"http://example.com/is_root":true}`,
  4. `{"kty":"oct","k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"}`
  5. )
  1. "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.lliDzOlRAdGUCfCHCPx_uisb6ZfZ1LRQa0OJLeYTTpY"

Token Verification

Built-inDescriptionWasm Support
output := io.jwt.verify_rs256(string, certificate)output is true if the RS256 signature of the input token is valid. certificate is the PEM encoded certificate, PEM encoded public key, or the JWK key (set) used to verify the RS256 signatureSDK-dependent
output := io.jwt.verify_rs384(string, certificate)output is true if the RS384 signature of the input token is valid. certificate is the PEM encoded certificate, PEM encoded public key, or the JWK key (set) used to verify the RS384 signatureSDK-dependent
output := io.jwt.verify_rs512(string, certificate)output is true if the RS512 signature of the input token is valid. certificate is the PEM encoded certificate, PEM encoded public key, or the JWK key (set) used to verify the RS512 signatureSDK-dependent
output := io.jwt.verify_ps256(string, certificate)output is true if the PS256 signature of the input token is valid. certificate is the PEM encoded certificate, PEM encoded public key or the JWK key (set) used to verify the PS256 signatureSDK-dependent
output := io.jwt.verify_ps384(string, certificate)output is true if the PS384 signature of the input token is valid. certificate is the PEM encoded certificate, PEM encoded public key or the JWK key (set) used to verify the PS384 signatureSDK-dependent
output := io.jwt.verify_ps512(string, certificate)output is true if the PS512 signature of the input token is valid. certificate is the PEM encoded certificate, PEM encoded public key or the JWK key (set) used to verify the PS512 signatureSDK-dependent
output := io.jwt.verify_es256(string, certificate)output is true if the ES256 signature of the input token is valid. certificate is the PEM encoded certificate, PEM encoded public key or the JWK key (set) used to verify the ES256 signatureSDK-dependent
output := io.jwt.verify_es384(string, certificate)output is true if the ES384 signature of the input token is valid. certificate is the PEM encoded certificate, PEM encoded public key or the JWK key (set) used to verify the ES384 signatureSDK-dependent
output := io.jwt.verify_es512(string, certificate)output is true if the ES512 signature of the input token is valid. certificate is the PEM encoded certificate, PEM encoded public key or the JWK key (set) used to verify the ES512 signatureSDK-dependent
output := io.jwt.verify_hs256(string, secret)output is true if the Secret signature of the input token is valid. secret is a plain text secret used to verify the HS256 signatureSDK-dependent
output := io.jwt.verify_hs384(string, secret)output is true if the Secret signature of the input token is valid. secret is a plain text secret used to verify the HS384 signatureSDK-dependent
output := io.jwt.verify_hs512(string, secret)output is true if the Secret signature of the input token is valid. secret is a plain text secret used to verify the HS512 signatureSDK-dependent
output := io.jwt.decode(string)output is of the form [header, payload, sig]. header and payload are object. sig is the hexadecimal representation of the signature on the token.SDK-dependent
output := io.jwt.decode_verify(string, constraints)output is of the form [valid, header, payload]. If the input token verifies and meets the requirements of constraints then valid is true and header and payload are objects containing the JOSE header and the JWT claim set. Otherwise, valid is false and header and payload are {}. Supports the following algorithms: HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512, PS256, PS384 and PS512.SDK-dependent

Note that the io.jwt.verify_XX built-in methods verify only the signature. They do not provide any validation for the JWT payload and any claims specified. The io.jwt.decode_verify built-in will verify the payload and all standard claims.

The input string is a JSON Web Token encoded with JWS Compact Serialization. JWE and JWS JSON Serialization are not supported. If nested signing was used, the header, payload and signature will represent the most deeply nested token.

For io.jwt.decode_verify, constraints is an object with the following members:

NameMeaningRequired
certA PEM encoded certificate, PEM encoded public key, or a JWK key (set) containing an RSA or ECDSA public key.See below
secretThe secret key for HS256, HS384 and HS512 verification.See below
algThe JWA algorithm name to use. If it is absent then any algorithm that is compatible with the key is accepted.Optional
issThe issuer string. If it is present the only tokens with this issuer are accepted. If it is absent then any issuer is accepted.Optional
timeThe time in nanoseconds to verify the token at. If this is present then the exp and nbf claims are compared against this value. If it is absent then they are compared against the current time.Optional
audThe audience that the verifier identifies with. If this is present then the aud claim is checked against it. If it is absent then the aud claim must be absent too.Optional

Exactly one of cert and secret must be present. If there are any unrecognized constraints then the token is considered invalid.

Token Verification Examples

The examples below use the following token:

  1. es256_token = "eyJ0eXAiOiAiSldUIiwgImFsZyI6ICJFUzI1NiJ9.eyJuYmYiOiAxNDQ0NDc4NDAwLCAiaXNzIjogInh4eCJ9.lArczfN-pIL8oUU-7PU83u-zfXougXBZj6drFeKFsPEoVhy9WAyiZlRshYqjTSXdaw8yw2L-ovt4zTUZb2PWMg"
Using JWKS

This example shows a two-step process to verify the token signature and then decode it for further checks of the payload content. This approach gives more flexibility in verifying only the claims that the policy needs to enforce.

  1. jwks = `{
  2. "keys": [{
  3. "kty":"EC",
  4. "crv":"P-256",
  5. "x":"z8J91ghFy5o6f2xZ4g8LsLH7u2wEpT2ntj8loahnlsE",
  6. "y":"7bdeXLH61KrGWRdh7ilnbcGQACxykaPKfmBccTHIOUo"
  7. }]
  8. }`
  1. io.jwt.verify_es256(es256_token, jwks) # Verify the token with the JWKS
  2. [header, payload, _] := io.jwt.decode(es256_token) # Decode the token
  3. payload.iss == "xxx" # Ensure the issuer (`iss`) claim is the expected value
  1. +-----------------------------+--------------------------------+
  2. | header | payload |
  3. +-----------------------------+--------------------------------+
  4. | {"alg":"ES256","typ":"JWT"} | {"iss":"xxx","nbf":1444478400} |
  5. +-----------------------------+--------------------------------+

The next example shows doing the token signature verification, decoding, and content checks all in one call using io.jwt.decode_verify. Note that this gives less flexibility in validating the payload content as all claims defined in the JWT spec are verified with the provided constraints.

  1. [valid, header, payload] := io.jwt.decode_verify(es256_token, {
  2. "cert": jwks,
  3. "iss": "xxx",
  4. })
  1. +-----------------------------+--------------------------------+-------+
  2. | header | payload | valid |
  3. +-----------------------------+--------------------------------+-------+
  4. | {"alg":"ES256","typ":"JWT"} | {"iss":"xxx","nbf":1444478400} | true |
  5. +-----------------------------+--------------------------------+-------+
Using PEM encoded X.509 Certificate

The following examples will demonstrate verifying tokens using an X.509 Certificate defined as:

  1. cert = `-----BEGIN CERTIFICATE-----
  2. MIIBcDCCARagAwIBAgIJAMZmuGSIfvgzMAoGCCqGSM49BAMCMBMxETAPBgNVBAMM
  3. CHdoYXRldmVyMB4XDTE4MDgxMDE0Mjg1NFoXDTE4MDkwOTE0Mjg1NFowEzERMA8G
  4. A1UEAwwId2hhdGV2ZXIwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATPwn3WCEXL
  5. mjp/bFniDwuwsfu7bASlPae2PyWhqGeWwe23Xlyx+tSqxlkXYe4pZ23BkAAscpGj
  6. yn5gXHExyDlKo1MwUTAdBgNVHQ4EFgQUElRjSoVgKjUqY5AXz2o74cLzzS8wHwYD
  7. VR0jBBgwFoAUElRjSoVgKjUqY5AXz2o74cLzzS8wDwYDVR0TAQH/BAUwAwEB/zAK
  8. BggqhkjOPQQDAgNIADBFAiEA4yQ/88ZrUX68c6kOe9G11u8NUaUzd8pLOtkKhniN
  9. OHoCIHmNX37JOqTcTzGn2u9+c8NlnvZ0uDvsd1BmKPaUmjmm
  10. -----END CERTIFICATE-----`

This example shows a two-step process to verify the token signature and then decode it for further checks of the payload content. This approach gives more flexibility in verifying only the claims that the policy needs to enforce.

  1. io.jwt.verify_es256(es256_token, cert) # Verify the token with the certificate
  2. [header, payload, _] := io.jwt.decode(es256_token) # Decode the token
  3. payload.iss == "xxx" # Ensure the issuer claim is the expected value
  1. +-----------------------------+--------------------------------+
  2. | header | payload |
  3. +-----------------------------+--------------------------------+
  4. | {"alg":"ES256","typ":"JWT"} | {"iss":"xxx","nbf":1444478400} |
  5. +-----------------------------+--------------------------------+

The next example shows doing the same token signature verification, decoding, and content checks but instead with a single call to io.jwt.decode_verify. Note that this gives less flexibility in validating the payload content as all claims defined in the JWT spec are verified with the provided constraints.

  1. [valid, header, payload] := io.jwt.decode_verify( # Decode and verify in one-step
  2. es256_token,
  3. { # With the supplied constraints:
  4. "cert": cert, # Verify the token with the certificate
  5. "iss": "xxx", # Ensure the issuer claim is the expected value
  6. }
  7. )
  1. +-----------------------------+--------------------------------+-------+
  2. | header | payload | valid |
  3. +-----------------------------+--------------------------------+-------+
  4. | {"alg":"ES256","typ":"JWT"} | {"iss":"xxx","nbf":1444478400} | true |
  5. +-----------------------------+--------------------------------+-------+
Round Trip - Sign and Verify

This example shows how to encode a token, verify, and decode it with the different options available.

Start with using the io.jwt.encode_sign_raw built-in:

  1. raw_result_hs256 := io.jwt.encode_sign_raw(
  2. `{"alg":"HS256","typ":"JWT"}`,
  3. `{}`,
  4. `{"kty":"oct","k":"Zm9v"}` # "Zm9v" == base64url.encode_no_pad("foo")
  5. )
  6. # Important!! - Use the un-encoded plain text secret to verify and decode
  7. raw_result_valid_hs256 := io.jwt.verify_hs256(raw_result_hs256, "foo")
  8. raw_result_parts_hs256 := io.jwt.decode_verify(raw_result_hs256, {"secret": "foo"})
  1. +----------------------------------------------------------------------------------------+---------------------------------------+------------------------+
  2. | raw_result_hs256 | raw_result_parts_hs256 | raw_result_valid_hs256 |
  3. +----------------------------------------------------------------------------------------+---------------------------------------+------------------------+
  4. | "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.Duw7jWmGY54yEu6kcqd2w1TKp1EspzboBnx8EeMc-z0" | [true,{"alg":"HS256","typ":"JWT"},{}] | true |
  5. +----------------------------------------------------------------------------------------+---------------------------------------+------------------------+

Now encode the and sign the same token contents but with io.jwt.encode_sign instead of the raw varient.

  1. result_hs256 := io.jwt.encode_sign(
  2. {
  3. "alg":"HS256",
  4. "typ":"JWT"
  5. },
  6. {},
  7. {
  8. "kty":"oct",
  9. "k":"Zm9v"
  10. }
  11. )
  12. # Important!! - Use the un-encoded plain text secret to verify and decode
  13. result_parts_hs256 := io.jwt.decode_verify(result_hs256, {"secret": "foo"})
  14. result_valid_hs256 := io.jwt.verify_hs256(result_hs256, "foo")
  1. +--------------------------------------------------------------------------------------------+---------------------------------------+--------------------+
  2. | result_hs256 | result_parts_hs256 | result_valid_hs256 |
  3. +--------------------------------------------------------------------------------------------+---------------------------------------+--------------------+
  4. | "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.e30.h4crob8QjgDq0JlZpf5mtylPvUzULS0XzdbG2-z_YKc" | [true,{"alg":"HS256","typ":"JWT"},{}] | true |
  5. +--------------------------------------------------------------------------------------------+---------------------------------------+--------------------+

Note that the resulting encoded token is different from the first example using io.jwt.encode_sign_raw. The reason is that the io.jwt.encode_sign function is using canonicalized formatting for the header and payload whereas io.jwt.encode_sign_raw does not change the whitespace of the strings passed in. The decoded and parsed JSON values are still the same.

Time

Built-inDescriptionWasm Support
output := time.now_ns()output is a number representing the current time since epoch in nanoseconds.SDK-dependent
output := time.parse_ns(layout, value)output is a number representing the time value in nanoseconds since epoch. See the Go time package documentation for more details on layout.SDK-dependent
output := time.parse_rfc3339_ns(value)output is a number representing the time value in nanoseconds since epoch.SDK-dependent
output := time.parse_duration_ns(duration)output is a number representing the duration duration in nanoseconds. See the Go time package documentation for more details on duration.SDK-dependent
output := time.date(ns)
output := time.date([ns, tz])
output is of the form [year, month, day], which includes the year, month (0-12), and day (0-31) as numbers representing the date from the nanoseconds since epoch (ns) in the timezone (tz), if supplied, or as UTC.SDK-dependent
output := time.clock(ns)
output := time.clock([ns, tz])
output is of the form [hour, minute, second], which outputs the hour, minute (0-59), and second (0-59) as numbers representing the time of day for the nanoseconds since epoch (ns) in the timezone (tz), if supplied, or as UTC.SDK-dependent
day := time.weekday(ns)
day := time.weekday([ns, tz])
outputs the day as string representing the day of the week for the nanoseconds since epoch (ns) in the timezone (tz), if supplied, or as UTC.SDK-dependent
output := time.add_date(ns, years, months, days)output is a number representing the time since epoch in nanoseconds after adding the years, months and days to ns. See the Go time package documentation for more details on add_date.SDK-dependent
output := time.diff(ns1, ns2)
output := time.diff([ns1, tz1], [ns2, tz2])
output is of the form [year(s), month(s), day(s), hour(s), minute(s), second(s)], which outputs year(s), month(s) (0-11), day(s) (0-30), hour(s)(0-23), minute(s)(0-59) and second(s)(0-59) as numbers representing the difference between the the two timestamps in nanoseconds since epoch (ns1 and ns2), in the timezones (tz1 and tz2, respectively), if supplied, or as UTC.SDK-dependent

Multiple calls to the time.now_ns built-in function within a single policy evaluation query will always return the same value.

Timezones can be specified as

  • an IANA Time Zone string e.g. “America/New_York”
  • “UTC” or “”, which are equivalent to not passing a timezone (i.e. will return as UTC)
  • “Local”, which will use the local timezone.

Note that the opa executable will need access to the timezone files in the environment it is running in (see the Go time.LoadLocation() documentation for more information).

Cryptography

Built-inDescriptionWasm Support
output := crypto.x509.parse_certificates(certs)certs is base64 encoded DER or PEM data containing one or more certificates or a PEM string of one or more certificates. output is an array of X.509 certificates represented as JSON objects.SDK-dependent
output := crypto.x509.parse_and_verify_certificates(certs)certs is base64 encoded DER or PEM data containing two or more certificates where the first is a root CA, the last is a leaf certificate, and all others are intermediate CAs. output is of the form [valid, certs]. If the input certificate chain could be verified then valid is true and certs is an array of X.509 certificates represented as JSON objects. If the input certificate chain could not be verified then valid is false and certs is [].SDK-dependent
output := crypto.x509.parse_certificate_request(csr)csr is a base64 string containing either a PEM encoded or DER CSR or a string containing a PEM CSR.output is an X.509 CSR represented as a JSON object.SDK-dependent
output := crypto.md5(string)output is string md5 hashed.SDK-dependent
output := crypto.sha1(string)output is string sha1 hashed.SDK-dependent
output := crypto.sha256(string)output is string sha256 hashed.SDK-dependent

Graphs

Built-inDescriptionWasm Support
walk(x, [path, value])walk is a relation that produces path and value pairs for documents under x. path is array representing a pointer to value in x. Queries can use walk to traverse documents nested under x (recursively).
output := graph.reachable(graph, initial)output is the set of vertices reachable from the initial vertices in the directed graph. initial is a set or array of vertices, and graph is an object containing a set or array of neighboring vertices.

A common class of recursive rules can be reduced to a graph reachability problem, so graph.reachable is useful for more than just graph analysis. This usually requires some pre- and postprocessing. The following example shows you how to “flatten” a hierarchy of access permissions.

  1. package graph_reachable_example
  2. org_chart_data = {
  3. "ceo": {},
  4. "human_resources": {"owner": "ceo", "access": ["salaries", "complaints"]},
  5. "staffing": {"owner": "human_resources", "access": ["interviews"]},
  6. "internships": {"owner": "staffing", "access": ["blog"]}
  7. }
  8. org_chart_graph[entity_name] = edges {
  9. org_chart_data[entity_name]
  10. edges := {neighbor | org_chart_data[neighbor].owner == entity_name}
  11. }
  12. org_chart_permissions[entity_name] = access {
  13. org_chart_data[entity_name]
  14. reachable := graph.reachable(org_chart_graph, {entity_name})
  15. access := {item | reachable[k]; item := org_chart_data[k].access[_]}
  16. }
  1. org_chart_permissions[entity_name]
  1. +-------------------+-----------------------------------------------+
  2. | entity_name | org_chart_permissions[entity_name] |
  3. +-------------------+-----------------------------------------------+
  4. | "ceo" | ["salaries","complaints","interviews","blog"] |
  5. | "human_resources" | ["salaries","complaints","interviews","blog"] |
  6. | "staffing" | ["interviews","blog"] |
  7. | "internships" | ["blog"] |
  8. +-------------------+-----------------------------------------------+

HTTP

Built-inDescriptionWasm Support
response := http.send(request)http.send executes an HTTP request and returns a response.SDK-dependent

The request object parameter may contain the following fields:

FieldRequiredTypeDescription
urlyesstringHTTP URL to specify in the request (e.g., https://www.openpolicyagent.org).
methodyesstringHTTP method to specify in request (e.g., “GET”, “POST”, “PUT”, etc.)
bodynoanyHTTP message body to include in request. The value will be serialized to JSON.
raw_bodynostringHTTP message body to include in request. The value WILL NOT be serialized. Use this for non-JSON messages.
headersnoobjectHTTP headers to include in the request (e.g,. {“X-Opa”: “rules”}).
enable_redirectnobooleanFollow HTTP redirects. Default: false.
force_json_decodenobooleanDecode the HTTP response message body as JSON even if the Content-Type header is missing. Default: false.
tls_use_system_certsnobooleanUse the system certificate pool. Default: true when tls_ca_cert, tls_ca_cert_file, tls_ca_cert_env_variable are unset. Ignored on Windows due to the system certificate pool not being accessible in the same way as it is for other platforms.
tls_ca_certnostringString containing a root certificate in PEM encoded format.
tls_ca_cert_filenostringPath to file containing a root certificate in PEM encoded format.
tls_ca_cert_env_variablenostringEnvironment variable containing a root certificate in PEM encoded format.
tls_client_certnostringString containing a client certificate in PEM encoded format.
tls_client_cert_filenostringPath to file containing a client certificate in PEM encoded format.
tls_client_cert_env_variablenostringEnvironment variable containing a client certificate in PEM encoded format.
tls_client_keynostringString containing a key in PEM encoded format.
tls_client_key_filenostringPath to file containing a key in PEM encoded format.
tls_client_key_env_variablenostringEnvironment variable containing a client key in PEM encoded format.
timeoutnostring or numberTimeout for the HTTP request with a default of 5 seconds (5s). Numbers provided are in nanoseconds. Strings must be a valid duration string where a duration string is a possibly signed sequence of decimal numbers, each with optional fraction and a unit suffix, such as “300ms”, “-1.5h” or “2h45m”. Valid time units are “ns”, “us” (or “µs”), “ms”, “s”, “m”, “h”. A zero timeout means no timeout.
tls_insecure_skip_verifynoboolAllows for skipping TLS verification when calling a network endpoint. Not recommended for production.
tls_server_namenostringSets the hostname that is sent in the client Server Name Indication and that be will be used for server certificate validation. If this is not set, the value of the Host header (if present) will be used. If neither are set, the host name from the requested URL is used.
cachenobooleanCache HTTP response across OPA queries. Default: false.
force_cachenobooleanCache HTTP response across OPA queries and override cache directives defined by the server. Default: false.
force_cache_duration_secondsnonumberIf force_cache is set, this field specifies the duration in seconds for the freshness of a cached response.
caching_modenostringControls the format in which items are inserted into the inter-query cache. Allowed modes are serialized and deserialized. In the serialized mode, items will be serialized before inserting into the cache. This mode is helpful if memory conservation is preferred over higher latency during cache lookup. This is the default mode. In the deserialized mode, an item will be inserted in the cache without any serialization. This means when items are fetched from the cache, there won’t be a need to decode them. This mode helps to make the cache lookup faster at the expense of more memory consumption. If this mode is enabled, the configured caching.inter_query_builtin_cache.max_size_bytes value will be ignored. This means an unlimited cache size will be assumed.
raise_errornoboolIf raise_error is set, errors returned by http.send will halt policy evaluation. Default: true.

If the Host header is included in headers, its value will be used as the Host header of the request. The url parameter will continue to specify the server to connect to.

When sending HTTPS requests with client certificates at least one the following combinations must be included

  • tls_client_cert and tls_client_key
  • tls_client_cert_file and tls_client_key_file
  • tls_client_cert_env_variable and tls_client_key_env_variable

To validate TLS server certificates, the user must also provide trusted root CA certificates through the tls_ca_cert, tls_ca_cert_file and tls_ca_cert_env_variable fields. If the tls_use_system_certs field is true, the system certificate pool will be used as well as any additional CA certificates.

The response object parameter will contain the following fields:

FieldTypeDescription
statusstringHTTP status message (e.g., “200 OK”).
status_codenumberHTTP status code (e.g., 200). If raise_error is false, this field will be set to 0 if http.send encounters an error.
bodyanyAny JSON value. If the HTTP response message body was not deserialized from JSON, this field is set to null.
raw_bodystringThe entire raw HTTP response message body represented as a string.
headersobjectAn object containing the response headers. The values will be an array of strings, repeated headers are grouped under the same keys with all values in the array.
errorobjectIf raise_error is false, this field will represent the error encountered while running http.send. The error object contains a message key which holds the actual error message and a code key which represents if the error was caused due to a network issue or during policy evaluation.

By default, an error returned by http.send halts the policy evaluation. This behaviour can be altered such that instead of halting evaluation, if http.send encounters an error, it can return a response object with status_code set to 0 and error describing the actual error. This can be activated by setting the raise_error field in the request object to false.

If the cache field in the request object is true, http.send will return a cached response after it checks its freshness and validity.

http.send uses the Cache-Control and Expires response headers to check the freshness of the cached response. Specifically if the max-age Cache-Control directive is set, http.send will use it to determine if the cached response is fresh or not. If max-age is not set, the Expires header will be used instead.

If the cached response is stale, http.send uses the Etag and Last-Modified response headers to check with the server if the cached response is in fact still fresh. If the server responds with a 200 (OK) response, http.send will update the cache with the new response. On a 304 (Not Modified) server response, http.send will update the headers in cached response with their corresponding values in the 304 response.

The force_cache field can be used to override the cache directives defined by the server. This field is used in conjunction with the force_cache_duration_seconds field. If force_cache is true, then force_cache_duration_seconds must be specified and http.send will use this value to check the freshness of the cached response.

Also, if force_cache is true, it overrides the cache field.

http.send uses the Date response header to calculate the current age of the response by comparing it with the current time. This value is used to determine the freshness of the cached response. As per https://tools.ietf.org/html/rfc7231#section-7.1.1.2, an origin server MUST NOT send a Date header field if it does not have a clock capable of providing a reasonable approximation of the current instance in Coordinated Universal Time. Hence, if http.send encounters a scenario where current age of the response is represented as a negative duration, the cached response will be considered as stale.

The table below shows examples of calling http.send:

ExampleComments
Accessing Google using System Cert Poolhttp.send({“method”: “get”, “url”: “https://www.google.com“, “tls_use_system_certs”: true })
Files containing TLS materialhttp.send({“method”: “get”, “url”: “https://127.0.0.1:65331“, “tls_ca_cert_file”: “testdata/ca.pem”, “tls_client_cert_file”: “testdata/client-cert.pem”, “tls_client_key_file”: “testdata/client-key.pem”})
Environment variables containing TLS materialhttp.send({“method”: “get”, “url”: “https://127.0.0.1:65360“, “tls_ca_cert_env_variable”: “CLIENT_CA_ENV”, “tls_client_cert_env_variable”: “CLIENT_CERT_ENV”, “tls_client_key_env_variable”: “CLIENT_KEY_ENV”})

Net

Built-inDescriptionWasm Support
net.cidr_contains(cidr, cidr_or_ip)output is true if cidr_or_ip (e.g. 127.0.0.64/26 or 127.0.0.1) is contained within cidr (e.g. 127.0.0.1/24) and false otherwise. Supports both IPv4 and IPv6 notations.
output := net.cidr_contains_matches(cidrs, cidrs_or_ips)output is a set of tuples identifying matches where cidrs_or_ips are contained within cidrs. This function is similar to net.cidr_contains except it allows callers to pass collections of CIDRs or IPs as arguments and returns the matches (as opposed to a boolean result indicating a match between two CIDRs/IPs.) See below for examples.SDK-dependent
net.cidr_intersects(cidr1, cidr2)output is true if cidr1 (e.g. 192.168.0.0/16) overlaps with cidr2 (e.g. 192.168.1.0/24) and false otherwise. Supports both IPv4 and IPv6 notations.
net.cidr_expand(cidr)output is the set of hosts in cidr (e.g., net.cidr_expand(“192.168.0.0/30”) generates 4 hosts: {“192.168.0.0”, “192.168.0.1”, “192.168.0.2”, “192.168.0.3”}SDK-dependent
net.cidr_merge(cidrs_or_ips)output is the smallest possible set of CIDRs obtained after merging the provided list of IP addresses and subnets in cidrs_or_ips (e.g., net.cidr_merge([“192.0.128.0/24”, “192.0.129.0/24”]) generates {“192.0.128.0/23”}. This function merges adjacent subnets where possible, those contained within others and also removes any duplicates. Supports both IPv4 and IPv6 notations.SDK-dependent

net.cidr_contains_matches examples

The output := net.cidr_contains_matches(a, b) function allows callers to supply strings, arrays, sets, or objects for either a or b. The output value in all cases is a set of tuples (2-element arrays) that identify matches, i.e., elements of b contained by elements of a. The first tuple element refers to the match in a and the second tuple element refers to the match in b.

Input TypeOutput Type
stringstring
arrayarray index
setset element
objectobject key
  1. package netcidrcontainsmatches

If both operands are string values the function is similar to net.cidr_contains.

  1. net.cidr_contains_matches("1.1.1.0/24", "1.1.1.128")
  1. [
  2. [
  3. "1.1.1.0/24",
  4. "1.1.1.128"
  5. ]
  6. ]

Either (or both) operand(s) may be an array, set, or object.

  1. net.cidr_contains_matches(["1.1.1.0/24", "1.1.2.0/24"], "1.1.1.128")
  1. [
  2. [
  3. 0,
  4. "1.1.1.128"
  5. ]
  6. ]

The array/set/object elements may be arrays. In that case, the first element must be a valid CIDR/IP.

  1. net.cidr_contains_matches([["1.1.0.0/16", "foo"], "1.1.2.0/24"], ["1.1.1.128", ["1.1.254.254", "bar"]])
  1. [
  2. [
  3. 0,
  4. 0
  5. ],
  6. [
  7. 0,
  8. 1
  9. ]
  10. ]

If the operand is a set, the outputs are matching elements. If the operand is an object, the outputs are matching keys.

  1. net.cidr_contains_matches({["1.1.0.0/16", "foo"], "1.1.2.0/24"}, {"x": "1.1.1.128", "y": ["1.1.254.254", "bar"]})
  1. [
  2. [
  3. [
  4. "1.1.0.0/16",
  5. "foo"
  6. ],
  7. "x"
  8. ],
  9. [
  10. [
  11. "1.1.0.0/16",
  12. "foo"
  13. ],
  14. "y"
  15. ]
  16. ]

UUID

Built-inDescriptionWasm Support
output := uuid.rfc4122(str)output is string representing a version 4 uuid. For any given str the output will be consistent throughout a query evaluation.SDK-dependent

Semantic Versions

Built-inDescriptionWasm Support
output := semver.is_valid(str)output is a boolean. true means the input is a valid SemVer string (e.g. “1.0.0”). false is returned for invalid version strings and non-string input.SDK-dependent
output := semver.compare(str, str)output is a number. -1 means the version in the first operand is less than the second. 1 means the version in the first operand is greater than the second. 0 means the versions are equal. Only valid SemVer strings are accepted e.g. 1.2.3 or 0.1.0SDK-dependent

Rego

Built-inDescriptionWasm Support
output := rego.parse_module(filename, string)rego.parse_module parses the input string as a Rego module and returns the AST as a JSON object output.SDK-dependent

OPA

Built-inDescriptionWasm Support
output := opa.runtime()opa.runtime returns a JSON object output that describes the runtime environment where OPA is deployed. Caution: Policies that depend on the output of opa.runtime may return different answers depending on how OPA was started. If possible, prefer using an explicit input or data value instead of opa.runtime. The output of opa.runtime will include a “config” key if OPA was started with a configuration file. The output of opa.runtime will include a “env” key containing the environment variables that the OPA process was started with. The output of opa.runtime will include “version” and “commit” keys containing the semantic version and build commit of OPA.SDK-dependent

Debugging

Built-inDescriptionWasm Support
trace(string)trace outputs the debug message string as a Note event in the query explanation. For example, trace(“Hello There!”) includes Note “Hello There!” in the query explanation. To print variables, use sprintf. For example, person := “Bob”; trace(sprintf(“Hello There! %v”, [person])) will emit Note “Hello There! Bob”.SDK-dependent

By default, explanations are disabled. The following table summarizes how you can enable tracing:

APIParameterExampleMemo
CLI—explainopa eval —explain=notes —format=pretty ‘trace(“hello world”)’
HTTPexplain=notescurl localhost:8181/v1/data/example/allow?explain=notes&pretty
REPLnotesn/aThe “notes” command enables trace explanations. See help for more details.

Reserved Names

The following words are reserved and cannot be used as variable names, rule names, or dot-access style reference arguments:

  1. as
  2. default
  3. else
  4. false
  5. import
  6. package
  7. not
  8. null
  9. some
  10. true
  11. with

Grammar

Rego’s syntax is defined by the following grammar:

  1. module = package { import } policy
  2. package = "package" ref
  3. import = "import" package [ "as" var ]
  4. policy = { rule }
  5. rule = [ "default" ] rule-head { rule-body }
  6. rule-head = var [ "(" rule-args ")" ] [ "[" term "]" ] [ ( ":=" | "=" ) term ]
  7. rule-args = term { "," term }
  8. rule-body = [ "else" [ "=" term ] ] "{" query "}"
  9. query = literal { ( ";" | ( [CR] LF ) ) literal }
  10. literal = ( some-decl | expr | "not" expr ) { with-modifier }
  11. with-modifier = "with" term "as" term
  12. some-decl = "some" var { "," var }
  13. expr = term | expr-call | expr-infix
  14. expr-call = var [ "." var ] "(" [ term { "," term } ] ")"
  15. expr-infix = [ term "=" ] term infix-operator term
  16. term = ref | var | scalar | array | object | set | array-compr | object-compr | set-compr
  17. array-compr = "[" term "|" rule-body "]"
  18. set-compr = "{" term "|" rule-body "}"
  19. object-compr = "{" object-item "|" rule-body "}"
  20. infix-operator = bool-operator | arith-operator | bin-operator
  21. bool-operator = "==" | "!=" | "<" | ">" | ">=" | "<="
  22. arith-operator = "+" | "-" | "*" | "/"
  23. bin-operator = "&" | "|"
  24. ref = ( var | array | object | set | array-compr | object-compr | set-compr | expr-call ) { ref-arg }
  25. ref-arg = ref-arg-dot | ref-arg-brack
  26. ref-arg-brack = "[" ( scalar | var | array | object | set | "_" ) "]"
  27. ref-arg-dot = "." var
  28. var = ( ALPHA | "_" ) { ALPHA | DIGIT | "_" }
  29. scalar = string | NUMBER | TRUE | FALSE | NULL
  30. string = STRING | raw-string
  31. raw-string = "`" { CHAR-"`" } "`"
  32. array = "[" term { "," term } "]"
  33. object = "{" object-item { "," object-item } "}"
  34. object-item = ( scalar | ref | var ) ":" term
  35. set = empty-set | non-empty-set
  36. non-empty-set = "{" term { "," term } "}"
  37. empty-set = "set(" ")"

The grammar defined above makes use of the following syntax. See the Wikipedia page on EBNF for more details:

  1. [] optional (zero or one instances)
  2. {} repetition (zero or more instances)
  3. | alternation (one of the instances)
  4. () grouping (order of expansion)
  5. STRING JSON string
  6. NUMBER JSON number
  7. TRUE JSON true
  8. FALSE JSON false
  9. NULL JSON null
  10. CHAR Unicode character
  11. ALPHA ASCII characters A-Z and a-z
  12. DIGIT ASCII characters 0-9
  13. CR Carriage Return
  14. LF Line Feed