Adaptive Authentication
Identify Platform implements an adaptive (Multi-factor or MFA) authentication solution that allows you to customize it to whatever your needs may be.
This process requires the following calls from a client:
/Security/StartAuthentication
to initiate authentication.- Zero or more calls to /Security/StartAuthentication to respond to an authentication challenge or challenges (in certain situations, the call to
/Security/StarAuthentication
logs in the user, in which case, there is no need to call /Security/AdvanceAuthentication).
Although the authentication process requires some flexibility on the part of the client, as the number and types of challenges may vary, and some challenges require a different type of response than others, the basic process for a successful login is as follows:
- The client requests authentication for a user by calling
/Security/StartAuthentication
and passing enough information to identify the user and tenant. - The server validates the user and tenant, and creates an MFA package that includes among other things, a session ID and zero or more authentication challenges for the client to answer.
The server caches the information and returns the MFA package to the client. Note that the number and type of challenges (user/password, one-time passcode, security question, etc.) depend on various factors that are configured by customer administrators, including the policies that are assigned to the user, which device a user signs in from, whether the IP address of the device is within the corporate firewall, etc. - The client calls
/Security/AdvanceAuthentication
to respond to an authentication challenge.
There may be a single challenge, multiple challenges in a list, or one challenge that must be answered first, followed by a list to choose from — the rest of this topic addresses each of these possibilities.
- If the client answers the challenge correctly, the server does one of the following:
- Logs the user in and returns LoginSuccess.
- Requests that the user answer another challenge mechanism.
- Notifies the client that an out of bounds (OOB) challenge is pending. The client must poll until the server indicates that the user has answered the challenge.
See "Responding to a pending OOB challenge" section.
The next section, Initiating authenticating, steps you through a basic scenario in which you call /Security/StartAuthentication
to generate a security challenge for a user and call /Security/AdvanceAuthentication
to respond to the challenge. Subsequent sections show how to handle a variety of authentication mechanisms and scenarios.
When you successfully call
/Security/AdvanceAuthentication
(or if the call to/Security/StartAuthenitcation
logs in the user), the server returns a set of cookies, including an authentication cookie. You must pass these cookies to all subsequent calls that you make on behalf of this user. See Authentication Cookies.
Initiating authentication
To initiate authentication, the client calls /Security/StartAuthentication
and passes User
, Version
,and TenantId
(optional if the hostname contains a tenant-specific URL or the user name contains a known alias):
/Security/StartAuthentication
{
"TenantId": "ABC1234",
"User": "mr.wright@doccraft",
"Version": "1.0"
}
After a call to /Security/StartAuthentication
, examine Summary
in the response from the server to determine what the client needs to do next:
Failure
— Only occurs if the user name or version is missing. In any case, the client should not allow a user to send a login request with a blank user name, so you should never see this error in a production system, but if you do, it means the client called the function without a user name or version.PodFqdn
— The fully-qualified domain name of the tenant. If the client calls/Security/StartAuthentication
with a system-generated tenant URL, while a custom URL is defined for the tenant, the call returns the custom tenant URL inPodFQDN
. Call/Security/StartAuthentication
again with the custom-defined tenant URL.NewPackage
— The server creates and returns an MFA package with one or more challenge mechanisms. Call/Security/AdvanceAuthentication
to respond to the first authentication mechanism. The next section explains how to respond to a new package with a single challenge mechanism.LoginSuccess
— Generally,/Security/StartAuthentication
does not complete the login process, however it is possible for it to do so. For example, if the call passes a valid authentication cookie, the server will log in the user and returnLoginSuccess
in the Summary.
Required rules and conditions for Logins
Below lists the required rules and conditions for logins when defining a profile. A cloud user can also set the rule for using/not using the profile.
The conditions for LoginRules
can be applied to a ProfileId
using one of the values below. ProfileId
is the ID of the authentication profile.
Operation (Rule) | Property | Property value |
---|---|---|
OpInCorpIpRange IP address inside the corporate IP range | IpAddress | Valid IP address Example: 12.345.67.89 |
OpNotInCorpIpRange IP address not inside the corporate IP range | IpAddress | Valid IP address Example: 12.345.67.89 |
OpExists Identity cookie exists | N/A | Valid IP address Example: 12.345.67.89 |
OpNotExists Identity Cookie does not exist | N/A | Valid IP address Example: 12.345.67.89 |
OpIsDayOfWeek Day of the week | DayOfWeek | Day of the week Example: U,0,1,2 - U = UTC time- 0 =Sun- 1 =MonNote: For local time, use L instead of U |
OpLessThan Date is less than the specified date | Date | Date Example: L,04/15/2019 - L =local time- U =UTC- Date in mm/dd/yyyy format |
OpGreaterThan Date is greater than the specified date | Date | Date Example: L,04/15/2019 - L =local time- U =UTC- Date in mm/dd/yyyy format |
OpBetween Range is in-between the specified dates | DateRange | Date range Example: L,04/15/2019,04/16/2019 - L =local time- U =UTC- Date in mm/dd/yyyy format |
OpBetween Range is in-between the specified times | Time | Time Example: L,11:00,12:00 - L =local Time- U =UTC- Time in hh:mm format |
OpEqual Equal to the defined condition | DeviceOs | Device OS level Examples: - iOS - Android - Windows - Linux - WindowsMobile |
OpEqual Equal to the defined condition | Browser | Browser types Examples: - Other - Chrome - Firefox - IE - Safari - MicrosoftEdge |
OpEqual Equal to the defined condition | RiskLevel | Risk level Examples: - Normal - No risk detected- Unknown - Undetermined risk- Low - Medium - High |
OpEqual Equal to the defined condition | CountryCode | Country code Examples: - SK - Slovakia- US - United States- etc |
OpNotEqual Not equal to the defined condition | DeviceOs | Device OS level Examples: - iOS - Android - Windows - Linux - WindowsMobile |
OpNotEqual Not equal to the defined condition | Browser | Browser types Examples: - Other - Chrome - Firefox - IE - Safari - MicrosoftEdge |
OpNotEqual Not equal to the defined condition | RiskLevel | Risk level Examples: - Normal - No risk detected- Unknown - Undetermined risk- Low - Medium - High |
OpNotEqual Not equal to the defined condition | CountryCode | Country code Examples: - SK - Slovakia- US - United States- etc |
Responding to a single challenge mechanism
This section shows how to respond to a single challenge mechanism. In this example, after the client calls /Security/StartAuthentication
to initiate authentication, the server returns a single, user-password (UP) challenge mechanism:
{
"ClientHints": {
"PersistDefault": False,
"AllowPersist": True,
"AllowForgotPassword": False
},
"Version": "1.0",
"SessionId": "1e5214e4-0921-4e9e-8ada-3ef2970f7c1f",
"Challenges": [
{
"Mechanisms": [
{
"AnswerType": "Text",
"Name": "UP",
"MechanismId": "4a23390d-dee9-4ead-aa33-2bacd93f81fa"
}
]
}
],
"Summary": "NewPackage",
"TenantId": "ABC1234"
}
Note the following about the response:
-
In the
Summary
field, "NewPackage
" indicates that the server has created a new MFA package. -
ClientHints
determine whether you can display a password link (AllowForgotPassword
) and "Keep me signed in" checkbox (AllowPersist
) for the user.PersistDefault
indicates the default forAllowPersist
. You can pass a different value to/Security/AdvanceAuthentication
if the user checks or unchecks the box in the login dialog that the client presents. -
In the
AnswerType
field, "Text
" indicates that the server expects a text string in response to this challenge mechanism. -
When you initiate authentication with a call to
/Security/StartAuthentication
, the server returns a new package whether the user that you pass is valid or invalid. This is to prevent hackers from brute-force guessing at login names. In the case of an invalid user name, the server returns a default challenge mechanism. When you call/Security/AdvanceAuthentication
to answer the challenge mechanism, the server returns an error message and Summary: "Undefined
" or "Failure
" in response.
Respond to a new package by calling /Security/AdvanceAuthentication
, passing TenantId
, SessionId
, and MechanismId
(retrieved from the response to /Security/StartAuthentication
) and answering the challenge mechanism:
/Security/AdvanceAuthentication
{
"TenantId": "ABC1234",
"SessionId": "1e5214e4-0921-4e9e-8ada-3ef2970f7c1f",
"MechanismId": "4a23390d-dee9-4ead-aa33-2bacd93f81fa",
"Action": "Answer",
"Answer": "Pass1234"
}
If the server validates the user (passed to /Security/StartAuthentication
) and the password (passed to /Security/AdvanceAuthentication
), it returns information about the user, and Summary
shows "LoginSuccess
", as shown here:
{
"success": true,
"Result":
{
"AuthLevel": "Normal",
"DisplayName": "MRWright",
"Auth": "6936714B84F54...",
"EmailAddress": "[email protected]",
"UserDirectory": "CDS",
"PodFqdn": "abc1234.my-dev.centrify.com",
"User": "mr.wright@doccraft",
"CustomerID": "ABC1234",
"SystemID": "ABC1234",
"SourceDsType": "CDS",
"Summary": "LoginSuccess"
}, "Message": null, "MessageID": null, "Exception": null, "ErrorID": null, "ErrorCode": null, "InnerExceptions": null
}
If the server does not validate the user, or if the password is incorrect, it returns an error message and shows Summary: "Undefined
" or "Failure
" in the response, as shown here:
{
"success": false,
"Result":
{
"Summary": "Undefined"
},
"Message": "Failed to login. Please try again or contact your system administrator.",
"MessageID": null,
"Exception": null,
"ErrorID": "c426637a-b8c3-46cb-be7a-4c7c6ceba131:00b917d8e98c4ccbb794dd0374c0c1f9",
"ErrorCode": null,
"InnerExceptions": null
}
The client must call /Security/StartAuthentication
again and pass a valid user name to initiate the authentication process, then call /Security/AdvanceAuthentication
and pass the correct password to advance the authentication.
Responding to multiple challenge mechanisms
In this example, after you call /Security/StartAuthentication
, the server returns multiple authentication mechanisms, shown here:
{
"success": true,
"Result": {
"ClientHints": {
"PersistDefault": False,
"AllowPersist": True,
"AllowForgotPassword": False
},
"Version": "1.0",
"SessionId": "1e5214e4-0921-4e9e-8ada-3ef2970f7c1f",
"Challenges": [
{
"Mechanisms": [
{
"AnswerType": "Text",
"Name": "UP",
"MechanismId": "4a23390d-dee9-4ead-aa33-2bacd93f81fa"
}
]
},
{
"Mechanisms": [
{
"AnswerType": "Text",
"PartialAddress": "centrify.com",
"EmailType": "Primary",
"Name": "EMAIL",
"MechanismId": "06d82f0c-cb09-4420-a64f-ecd9efda74e8"
},
{
"AnswerType": "Text",
"PartialDeviceAddress": "6098",
"Name": "SMS",
"MechanismId": "2bcddd0b-37b9-4a6b-b393-9cd03eb7c9aa"
},
{
"AnswerType": "Text",
"Question": "Tonight's Homework",
"Name": "SQ",
"MechanismId": "5778ff68-4e65-4ceb-b9e8-361e281228a8"
},
{
"AnswerType": "Text",
"PartialPhoneNumber": "6098",
"Name": "PF",
"MechanismId": "2f0a3e0c-bea8-4c91-95f0-b9cdd736f668"
},
{
"AnswerType": "Text",
"PartialPhoneNumber": "5290",
"Name": "PF",
"MechanismId": "415a2e99-371a-49e3-bf3b-267b1a83be96"
}
]
}
],
"Summary": "NewPackage",
"TenantId": "ABC1234"
}
The server returns two challenges:
- The first one defines a single, user-password mechanism. The client must answer this one first.
- The second one defines multiple mechanisms (SMS, SQ, PF, etc.); after answering the first challenge, the client must answer one of these mechanisms.
Call /Security/AdvanceAuthentication
to respond to the first challenge:
/Security/AdvanceAuthentication
{
"SessionId": "1e5214e4-0921-4e9e-8ada-3ef2970f7c1f",
"MechanismId": "4a23390d-dee9-4ead-aa33-2bacd93f81fa",
"Action": "Answer",
"Answer": "Pass1234"
}
The server responds with a request to answer the next challenge (Summary: StartNextChallenge
), shown here:
{
"success": true,
"Result":
{
"Summary": "StartNextChallenge"
},
"Message": null, "MessageID": null, "Exception": null, "ErrorID": null, "ErrorCode": null, "InnerExceptions": null
}
The value in the Summary field (StartNextChallenge
) indicates that there are additional challenges to which you must respond. It does not necessarily indicate that the response to the challenge was correct. To prevent hackers from guessing which challenge failed, the server may wait for all challenge responses before validating or invalidating the responses.
Call /Security/AdvanceAuthentication
to respond to one of the challenges, for example, the security question (SQ). The server provides all the information you need to present to the user for each challenge. For example, the Security challenge provides the text of the question ("Tonight's homework), the SMS challenge provides a partial number, etc. Note, however, that the server does not provide translations of the prompts. You are responsible for creating and translating prompts, if necessary, for your client.
/Security/AdvanceAuthentication
{
"TenantId": "ABC123",
"SessionId": "1e5214e4-0921-4e9e-8ada-3ef2970f7c1f",
"MechanismId": "5778ff68-4e65-4ceb-b9e8-361e281228a8",
"Action": "Answer",
"Answer": "math 101"
}
Check Summary to see if there are additional challenges to answer. Once you have correctly answered all challenges, the server returns a response (Summary: LoginSuccess
) that is similar to the following LoginSuccess response:
{
"SystemID": "ABC1234",
"DisplayName": ""MRWright"",
"EmailAddress": "[email protected]",
"PasswordExpDate": "Fri, 31 Dec 9999 15:59:59 GMT-08:00",
"CustomerID": "ABC1234",
"AuthLevel": "Normal",
"PodFqdn": "abc1234.my-dev.centrify.com",
"Auth": "C85562A8A3B425095981BFFD7D92F7...",
"User": "mr.wright@doccraft",
"UserDirectory": "CDS",
"Summary": "LoginSuccess",
"UserId": "c2c7bcc6-9560-44e0-8dff-5be221cd37ee",
"SourceDsType": "CDS"
}
"Summary": "LoginSuccess"
indicates that the server has authenticated the user.
The response includes information about the user, such as display name, email address, password expiration, and so on. It also includes UserId
, which you can pass to other API functions to get information about the user.
The response from
/Security/AdvanceAuthentication
includes the cookies that you must pass to each subsequent call on behalf of the validated user. See Authentication Cookies.
Responding to a pending OOB challenge
An out of bounds (OOB) mechanism is one in which the server contacts an outside device or system, for example, by sending an SMS message to a user's device, or an Email message to his or her email address. To complete authentication, a user must retrieve the message and follow the instructions, for example, by clicking an authentication link.
In this example, the server returns a new package in response to your call to /Security/StartAuthentication
or /Security/AdvanceAuthentication
that contains an OOB challenge mechanism such as this:
{
"AnswerType": "StartOob",
"Name": "EMAIL",
"MechanismId": "8110671b-7d6c-4604-98c5-4fd273f8063f-099e7f417e646300",
"PartialAddress": "acme.com"
}
You respond to the mechanism by calling /Security/AdvanceAuthentication
as follows:
/Security/AdvanceAuthentication
{
"TenantId": "ABC1234",
"SessionId": "1db90fe4-3b96-4c3e-a3c1-9a10fa7514c9-27f4e64e86ac08e8",
"MechanismId": "8110671b-7d6c-4604-98c5-4fd273f8063f-099e7f417e646300",
"Action": "StartOOB"
}
The server does the following:
- Sends an email message to the user's "
acme.com
" address" that contains a link to complete login. - Sends an "OOB pending" response to the client and waits for the client to answer.
{
"Summary": "OobPending"
}
The client should poll the server by calling /Security/AdvanceAuthentication
periodically (no more than once/second) until the value in Summary changes from OobPending
. In the payload, specify Poll
in the Action
field:
/Security/AdvanceAuthentication
{
"TenantId": "AB123",
"SessionId": "1db90fe4-3b96-4c3e-a3c1-9a10fa7514c9-27f4e64e86ac08e8",
"MechanismId": "8110671b-7d6c-4604-98c5-4fd273f8063f-099e7f417e646300",
"Action": "Poll"
}
Continue to poll until you see "Summary": "LoginSuccess"
, which indicates that the server has authenticated the user, or a failure message indicating that the server did not authenticate the user.
Authenticating a user with an expired password
This topic shows how to call the API to authenticate a user whose password has expired. Although the example is explicitly about how to handle a user with an expired password, it illustrates the broader point that in response to /Security/AdvanceAuthentication
, the server may return a new package that does any of the following:
- Removes, replaces, or adds mechanisms to existing challenges.
- Adds new challenges
- Removes existing challenges
When a client calls /Security/StartAuthentication
to initiate authentication, the server doesn't know whether the password has expired or not because the client has passed a user name, but not a password. The server validates the user and tenant and returns an MFA package with appropriate challenge mechanisms for the user — for example, a user-password challenge that must be answered first and a security-question challenge to be answered after the user-password challenge, such as these:
...
"Challenges":
[
{
"Mechanisms": [
{
"AnswerType": "Text",
"Name": "UP",
"MechanismId": "51b8ca6f-9b15-4cec-ba7c-ce20cc2bfb77"
}
]
},
{
"Mechanisms": [
{
"AnswerType": "Text",
"Question": "Tonight's Homework",
"Name": "SQ",
"MechanismId": "bd2f1c84-1026-4d63-aef1-a357b5e7ab37"
} ]
}
],
"Summary": "NewPackage",
"TenantId": "AB123"
After the client calls /Security/AdvanceAuthentication
to respond to the password challenge, the server is aware that the user's password has expired, and returns the following "New challenge mechanisms" package in response:
...
"Challenges": [
{
"Mechanisms": [
{
"AnswerType": "Text",
"Question": "Tonight's Homework",
"Name": "SQ",
"MechanismId": "bd2f1c84-1026-4d63-aef1-a357b5e7ab37"
}
]
},
{
"Mechanisms": [
{
"AnswerType": "Text",
"Name": "RESET",
"MechanismId": "35e70e0d-94a8-4d13-b4f2-ed5a314a908d"
}
]
}
],
"Summary": "NewPackage",
"TenantId": "ABC123"
Note the following about the response:
- The server sends a new package (
"Summary": "NewPackage",
) because the password is expired and the client needs to send a new response. - The server removes the user/password challenge from the response because it has already been answered. It caches the client's successful response to the challenge for future use.
- It moves the security question (SQ) challenge from second to first on the list — it hasn't been answered yet.
- It adds a new second challenge (RESET).
Call /Security/AdvanceAuthentication
to respond to the security-question challenge:
/Security/AdvanceAuthentication
{
"TenantId": "ABC123",
"SessionId": "81c60352-ee50-422c-b5c9-e73b55b8f314",
"MechanismId": "bd2f1c84-1026-4d63-aef1-a357b5e7ab37",
"Action": "Answer",
"Answer": "math 101"
}
The server returns the following response:
{
"Summary": "StartNextChallenge"
}
Call /Security/AdvanceAuthentication
again, this time to answer the reset challenge:
/Security/AdvanceAuthentication
{
"TenantId": "ABC1234",
"SessionId": "a3f66039-2ae4-4320-8200-426285d995e7",
"MechanismId": "35e70e0d-94a8-4d13-b4f2-ed5a314a908d",
"Action": "Answer",
"Answer": "Pass6789"
}
The server returns a response ("Summary": "LoginSuccess"
) similar to the following LoginSuccess response:
{
"success": True,
"Result":
{
{
"SystemID": "ABC1234",
"DisplayName": ""MRWright"",
"EmailAddress": "[email protected]",
...
"Summary": "LoginSuccess",
}
},
}
Handling redirects
As explained in Use your Tenant URL, Identity Platform identifies a tenant through tenant URLs, which are of three types:
- System-generated. Identity platform automatically generates a URL by prefixing the string '
my.centrify.com
' with the tenant ID. For example, tenant IDABC1234
forms tenant URLABC1234.my.centrify.com
. - Custom, created by client. An administrator creates a URL from a custom string, such as company name, prefixed to '
my.centrify.com
'. For example,acme.my.centrify.com
. - Preferred, a custom tenant ID that administrator designates as the default, or preferred URL to use.
If a preferred tenant URL exists, Identity Platform automatically directs logins from the system-generated URL to the preferred tenant URL. From the perspective of the API, if you call
/Security/Start/Authentication
using the system-generated tenant URL, you must redirect the call to the preferred URL. For example:
https://ABC1234.my.centrify.com/Security/StartAuthentication
{User: "user2", Version: "1.0"}
Although the call completes successfully, instead of returning an authentication package, it returns the preferred tenant URL in PodFqdn
, as shown here:
{
"success": true,
"Result":
{
"PodFqdn": "acme.my.centrify.com"
},
"Message": null, "MessageID": null, "Exception": null, "ErrorID": null, "ErrorCode": null, "InnerExceptions": null
}
In response, call /Security/Start/Authentication
again but specify the preferred URL from PodFqdn
:
https://acme.my.centrify.com/Security/StartAuthentication
{User: "user2", Version: "1.0"}
In response, /Security/Start/Authentication
returns a new authentication package ("Summary": "NewPackage"
) that you can use to authenticate the user, as shown here:
{
"success": true,
"Result":
{
"ClientHints":
{
"PersistDefault": false,
"AllowPersist": false,
"AllowForgotPassword": true
},
"Version": "1.0",
"SessionId": "7abd72d0-446b-4a51-bdd9-50b8027ec5fe-a479e2e0ff8d8820",
"Challenges":
[
{
"Mechanisms": [
{
"AnswerType": "Text",
"Name": "UP",
"MechanismId": "7f43d95c-22ba-4d63-bb15-8548923ad6ed-7439116a4971648e"
}
]
}
],
"Summary": "NewPackage",
"TenantId": "ABC1234"
},
"Message": null, "MessageID": null, "Exception": null, "ErrorID": null, "ErrorCode": null, "InnerExceptions": null
}
See Also
Updated almost 4 years ago