On this page
Okta Expression Language in Okta Identity Engine
Identity EngineOverview
This document details the features and syntax of Expression Language used for the following:
- Authentication policies of Identity Engine
- Access Certification campaigns (opens new window) and Entitlement Management policies for Okta Identity Governance
Expressions used outside of these areas should continue using the features and syntax of Expression Language. This document is updated as new capabilities are added to the language. Expression Language is based on a subset of SpEL functionality (opens new window).
Note: In this reference,
$placeholder
denotes a value that you need to replace with an appropriate variable. For example, inuser.profile.$profile_property
,$profile_property
can be replaced withfirstName
,lastName
,
Unsupported features
The following operators and functionalities offered by SpEL aren't supported in Expression Language:
- Decrement operator (opens new window)
- Increment operator (opens new window)
- Instanceof operator (opens new window)
- Between operator (opens new window)
- Assign (opens new window)
- Bean reference (opens new window)
- Constructor reference (opens new window)
- Function reference (opens new window)
- Type reference (opens new window)
- Variable reference (opens new window)
- Projection (opens new window)
- Qualified identifier (opens new window)
Reference attributes
Okta User Profile
When you create an Okta expression, you can reference any property that exists in an Okta User Profile in addition to some top-level User properties.
Note: You can't use the
user.status
expression with group rules. See Group rule operations (opens new window) and Create Group Rule (opens new window).
Syntax | Definitions | Examples |
---|---|---|
user.$property | user - references the Okta userproperty - top-level property variable nameValues: id , status , created , lastUpdated , passwordChanged , lastLogin | user.id user.status user.created |
user.profile.$profile_property | profile_property - references the user profile property, including custom-defined properties | user.profile.firstName user.profile.email |
Okta Device Profile
When you create an Okta expression, you can reference EDR attributes and any property that exists in an Okta Device Profile.
Syntax | Definitions | Examples |
---|---|---|
device.profile.$profile_property | profile_property - references a Device Profile property | device.profile.managed device.profile.registered |
device.provider.$vendor.$signal | vendor - references a vendor, such as wsc for Windows Security Center or zta for CrowdStrike signal - references the supported EDR signal by the vendor | device.provider.wsc.fireWall device.provider.wsc.autoUpdateSettings device.provider.zta.overall |
See Integrate with Endpoint Detection and Response solutions (opens new window) and Available EDR signals by vendor (opens new window) for details about vendor
and signal
.
Security context
You can specify certain rule conditions in authentication policies. Use expressions based on the security context of the app sign-on request. Security context is made up of the risk level (opens new window) and the matching User behaviors (opens new window) for the request.
Syntax | Definitions | Type | Examples | Usage |
---|---|---|---|---|
security.risk.level | security references the security context of the requestrisk references the risk (opens new window) context of the requestlevel is the risk level associated with the request | String | 'LOW' 'MEDIUM' 'HIGH' | security.risk.level == 'HIGH' security.risk.level != 'LOW' |
security.behaviors | security references the security context of the requestbehaviors is the list of matching User behaviors (opens new window) for the request, by name. | Array of Strings | {'New IP', 'New Device'} | security.behaviors.contains('New IP') && security.behaviors.contains('New Device') |
Login Context
Early AccessYou can specify the dynamic IdP. Use expressions based on the login context that holds the user's username
as the identifier
.
Syntax | Definitions | Type |
---|---|---|
login.identifier | login references the login context of the request. identifier references the user's username . | String |
Okta account management
Early AccessYou can specify certain Expression Language conditions in Okta account management policies (opens new window).
Syntax | Definitions | Type |
---|---|---|
accessRequest.$operation | accessRequest references the access context of the request. operation references the account management operation: enroll , unenroll , recover , or unlockAccount . | String |
accessRequest.authenticator.$id | accessRequest references the access context of the request. authenticator.id references an optional authenticator id , for example, the id of a custom authenticator. | String |
accessRequest.authenticator.$key | accessRequest references the access context of the request. authenticator.key references the authenticator key. | String |
Functions
Okta offers various functions to manipulate properties to generate a desired output. You can combine and nest functions inside a single expression.
Note: For the following expression examples, assume that the following properties exist in Okta and that the user has the associated values.
Attribute | Type | Data |
---|---|---|
user.created | ZonedDateTime | 2015-07-30T23:58:32.000Z |
user.firstName | String | "John" |
user.lastName | String | "Doe" |
user.email | String | "john.doe@okta.com" |
user.strArray | Array | {"one", "two"} |
user.intArray | Array | {1, 2, 3} |
user.stringDouble | String | "1.1" |
user.country | String | "United States" |
user.countryAlpha2 | String | "US" |
user.countryAlpha3 | String | "USA" |
user.isContractor | Boolean | False |
String functions
Function | Input parameter signature | Return type | Example | Output |
---|---|---|---|---|
$string_object.toUpperCase | - | String | 'test'.toUpperCase() | "TEST" |
user.profile.firstName.toUpperCase() | "JOHN" | |||
$string_object.toLowerCase | - | String | 'TEST'.toLowerCase() | "test" |
$string_object.substring | (int startIndex) | String | 'test.substring(1)' | "est" |
$string_object.substring | (int startIndex, int endIndex) | String | user.profile.firstName.substring(1,3) | "oh" |
$string_object.replace | (String match, String replacement) | String | 'hello'.replace('l', 'p') | "heppo" |
user.profile.firstName.replace('ohn', 'ames') | "James" | |||
$string_object.replaceFirst | (String match, String replacement) | String | 'hello'.replaceFirst('l', 'p') | "heplo" |
$string_object.length | - | Integer | 'test'.length() | 4 |
$string_object.removeSpaces | - | String | 'This is a test'.removeSpaces() | "Thisisatest" |
$string_object.contains | (String searchString) | Boolean | 'This is a test'.contains('test') | True |
'This is a test'.contains('Test') | False | |||
$string_object.substringBefore | (String searchString) | String | user.profile.email.substringBefore('@') | "john.doe" |
$string_object.substringAfter | (String searchString) | String | user.profile.email.substringAfter('@') | "okta.com" |
user.profile.email.substringAfter('.') | "doe@okta.com" |
Note: In the
substring
function,startIndex
is inclusive andendIndex
is exclusive.
Array functions
Function | Input parameter Signature | Return type | Example | Output |
---|---|---|---|---|
$array_object.contains | (Object searchItem) | Boolean | user.profile.intArray.contains(3) | True |
{1, 2, 3}.contains('one') | False | |||
$array_object.size | - | Integer | user.profile.strArray.size() | 2 |
$array_object.isEmpty | - | Boolean | {}.isEmpty() | True |
$array_object.add | (Object itemToAdd) | Array | user.profile.strArray.add('zero') | {"one", "two", "zero"} |
{'one', 'two'}.add('two') | {"one", "two", "two"} | |||
$array_object.remove | (Object itemToRemove) | Array | user.profile.intArray.remove(1) | {2, 3} |
{2, 3}.remove(1) | {2, 3} | |||
$array_object.flatten | - | Array | {\\{1}, {2, 3}\\}.flatten() | {1, 2, 3} |
user.profile.intArray.flatten() | {1, 2, 3} |
Conversion functions
Data conversion functions
Function | Return type | Example | Output |
---|---|---|---|
$string_object.toInteger | Integer | user.profile.stringDouble.toInteger() | 1 |
user.profile.email.toInteger() | An exception is thrown | ||
'-2147483649'.toInteger() | 2147483647 | ||
$string_object.toNumber | Double | user.profile.stringDouble.toNumber() | 1.1 |
'1.7'.toNumber() | 1.7 | ||
'123This is a test'.toNumber() | An exception is thrown | ||
$number_object.toInteger | Integer | 1.1.toInteger() | 1 |
-1.6.toInteger() | -2 | ||
2147483647.7.toInteger() | -2147483648 (Integer overflow) |
Note: The
toInteger
functions round the passed numeric value (or the String representation of the numeric value) either up or down to the nearest integer. Make sure to consider range limitations of the integer type when you convert to an integer with these functions.
Country code conversion functions
These functions convert between ISO 3166-1 2-character country codes (Alpha 2), 3-character country codes (Alpha 3), numeric country codes, and full ISO country names.
Function | Return type | Example | Output |
---|---|---|---|
$string_object.parseCountryCode | CountryCode | user.profile.country.parseCountryCode() | US (CountryCode object) |
user.profile.countryAlpha2.parseCountryCode() | US (CountryCode object) | ||
user.profile.countryAlpha3.parseCountryCode() | US (CountryCode object) | ||
'840'.parseCountryCode() | US (CountryCode object) | ||
$country_code_object.toAlpha2 | String | 'USA'.parseCountryCode().toAlpha2() | "US" |
$country_code_object.toAlpha3 | String | '840'.parseCountryCode().toAlpha3() | "USA" |
$country_code_object.toNumeric | String | 'United States'.parseCountryCode().toNumeric() | "840" |
$country_code_object.toName | String | 'US'.parseCountryCode().toName() | "United States" |
Note: You can call the
parseCountryCode
function on the string representations of ISO 3166-1 2-character country codes (Alpha 2), 3-character country codes (Alpha 3), numeric country codes, and country names. You can call the other four functions on country code objects and return the output in the format specified by the function names.
See the ISO 3166-1 online lookup tool (opens new window).
Group functions
Note: For the following expression examples, assume that the User is a member of the following Groups:
Group ID | Group name | Group type |
---|---|---|
00gak46y5hydV6NdM0g4 | Everyone | BUILT_IN |
00g1emaKYZTWRYYRRTSK | West Coast Users | OKTA_GROUP |
00garwpuyxHaWOkdV0g4 | West Coast Admins | OKTA_GROUP |
00gjitX9HqABSoqTB0g3 | Engineering Users | APP_GROUP |
Group functions take in a list of search criteria as input. Each search criterion is a key-value pair:
Key: Specifies the matching property. Currently supported keys are: group.id
, group.type
, and group.profile.name
.
Value: Specifies a list of matching values.
The group.id
and group.type
keys can match values that are exact.
The group.profile.name
key supports the operators EXACT
and STARTS_WITH
to identify exact matches or matches that include the value. If no operator is specified, the expression uses STARTS_WITH
. These operators can't be used with group.id
or group.type
.
Function | Return type | Example | Output |
---|---|---|---|
user.getGroups | Array | user.getGroups({'group.id': {'00gjitX9HqABSoqTB0g3'}}, {'group.profile.name': 'West Coast.*'}) | {} |
user.getGroups({'group.type': {'OKTA_GROUP'}}, {'group.profile.name': {'Everyone', 'West Coast Admins'}}) | A list of User Groups that contains the Groups with ID 00garwpuyxHaWOkdV0g4 | ||
user.getGroups({'group.profile.name': 'East Coast.*'}) | {} | ||
user.getGroups({'group.type': {'OKTA_GROUP', 'APP_GROUP'}}) | A list of User Groups that contains the Groups with IDs 00g1emaKYZTWRYYRRTSK , 00garwpuyxHaWOkdV0g4 , and 00gjitX9HqABSoqTB0g3 | ||
user.isMemberOf | Boolean | user.isMemberOf({'group.id': {'00gjitX9HqABSoqTB0g3', '00garwpuyxHaWOkdV0g4'}}, {'group.type': 'APP_GROUP'}) | True |
user.isMemberOf({'group.id': {'00gjitX9HqABSoqTB0g3', '00garwpuyxHaWOkdV0g4'}}, {'group.type': 'BUILT_IN'}) | False | ||
user.isMemberOf({'group.profile.name': 'West Coast', 'operator': 'STARTS_WITH' }) | True | ||
user.isMemberOf({'group.profile.name': 'West Coast', 'operator': 'EXACT' }) | False |
Linked Object function
Use this function to retrieve the user who's identified with the specified primary
relationship. You can then access the properties of that user.
- Function:
user.getLinkedObject($primaryName)
- Parameter: (String primaryName)
- Return Type: User
- Example:
user.getLinkedObject("manager").lastName
- Example Result:
Gates
Time functions
Note: For the following expression examples, assume that the current date and time is
2015-07-31T17:18:37.979Z
.
Function | Input parameter signature | Return type | Example | Output |
---|---|---|---|---|
DateTime.now | - | ZonedDateTime | DateTime.now() | 2015-07-31T17:18:37.979Z (The current date-time in the UTC time-zone) |
$string_object.parseWindowsTime | - | ZonedDateTime | '130828367179790000'.parseWindowsTime() | 2015-07-31T17:18:37.979Z |
$string_object.parseUnixTime | - | ZonedDateTime | '1438377580979'.parseUnixTime() | 2015-07-31T21:19:40.979Z |
$string_object.parseStringTime | - | ZonedDateTime | '2015-06-17T00:23:19.676Z'.parseStringTime() | 2015-06-17T00:23:19.676Z |
$string_object.parseStringTime | (String dateTimeFormat) | ZonedDateTime | '17 June 2015 00:23:19'.parseStringTime('dd MMMM yyyy HH:mm:ss') | 2015-06-17T00:23:19Z |
$zoned_date_time_object.toWindows | - | String | user.created.toWindows() | "130827743120000000" |
$zoned_date_time_object.toUnix | - | String | DateTime.now().toUnix() | "1438363117979" |
$zoned_date_time_object.toString | - | String | user.created.toString() | "2015-07-30T23:58:32Z" |
$zoned_date_time_object.toString | (String dateTimeFormat) | String | user.created.toString('MM/dd/yyyy') | "07/30/2015" |
$zoned_date_time_object.toZone | (String zoneId) | ZonedDateTime | Time.now().toZone('Asia/Tokyo') | 2015-08-01T02:18:37.979+09:00[Asia/Tokyo] |
$zoned_date_time_object.plusDays | (int days) | ZonedDateTime | user.created.plusDays(2) | 2015-08-01T23:58:32.000Z |
$zoned_date_time_object.plusHours | (int hours) | ZonedDateTime | user.created.plusHours(-1) | 2015-07-30T22:58:32.000Z |
$zoned_date_time_object.plusMinutes | (int minutes) | ZonedDateTime | user.created.plusMinutes(0) | 2015-07-30T23:58:32.000Z |
$zoned_date_time_object.plusSeconds | (int seconds) | ZonedDateTime | user.created.plusSeconds(0) | 2015-07-30T23:58:32.000Z |
$zoned_date_time_object.minusDays | (int days) | ZonedDateTime | Time.now().minusDays(3) | 2015-07-28T17:18:37.979Z |
$zoned_date_time_object.minusHours | (int hours) | ZonedDateTime | Time.now().minusHours(100) | 2015-07-27T13:18:37.979Z |
$zoned_date_time_object.minusMinutes | (int minutes) | ZonedDateTime | Time.now().minusMinutes(-1) | 2015-07-31T17:19:37.979Z |
$zoned_date_time_object.minusSeconds | (int seconds) | ZonedDateTime | Time.now().minusSeconds(2) | 2015-07-31T17:18:35.979Z |
$zoned_date_time_object.withinDays | (int days) | Boolean | user.created.withinDays(1) | True |
$zoned_date_time_object.withinHours | (int hours) | Boolean | user.created.withinHours(100) | True |
$zoned_date_time_object.withinMinutes | (int minutes) | Boolean | user.created.withinMinutes(2) | False |
$zoned_date_time_object.withinSeconds | (int seconds) | Boolean | user.created.withinSeconds(100) | False |
Note: Okta supports the use of the time zone IDs and aliases listed in the Time Zone Codes table.
Constants and operators
Common Action | Example |
---|---|
Refer to a String constant | 'Hello world' |
Refer to a Integer constant | 1234 |
Refer to a Number constant | 3.141 |
Refer to a Boolean constant | true |
Concatenate two strings | user.profile.firstName + user.profile.lastName |
Conditional expressions
The following rules apply to conditional expressions:
- Expressions must have valid syntax.
- Expressions must evaluate to Boolean.
- Expressions can't contain an assignment operator, such as
=
. - User properties referenced in an expression must exist.
The following functions are supported in conditional expressions:
- Any Expression Language function
- The
&&
operator to designate AND - The
||
operator to designate OR - The
!
operator to designate NOT - Standard relational operators including
<
,>
,<=
, and>=
Note: Use the double equals sign
==
to check for equality and!=
for inequality.
Examples
Expression | Output |
---|---|
user.profile.country == "United States" | True |
user.profile.intArray.contains(0) | False |
user.profile.isContractor || user.created.withinSeconds(0) | False |
You can use the ternary operator for performing IF, THEN, ELSE conditional logic inside the expression.
The format for a ternary conditional expression is: [Condition] ? [Value if TRUE] : [Value if FALSE]
Examples
If the middle initial isn't empty, include it as part of the full name using just the first character and appending a period.
user.profile.firstName + " " + (user.profile.middleInitial.length() == 0 ? "" : (user.profile.middleInitial.substring(0, 1) + ". ")) + user.profile.lastName
If the user is a contractor and is a member of the "West Coast Users" user group, output "West coast contractors", else output "Others".
user.profile.isContractor && user.isMemberOf({'group.profile.name': 'West Coast Users'}) ? "West coast contractors" : "Others"