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:

  1. The client requests authentication for a user by calling /Security/StartAuthentication and passing enough information to identify the user and tenant.
  2. 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.
  3. 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.

  1. 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 in PodFQDN. 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 return LoginSuccess 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)PropertyProperty value
OpInCorpIpRange

IP address inside the corporate IP range
IpAddressValid IP address

Example: 12.345.67.89
OpNotInCorpIpRange

IP address not inside the corporate IP range
IpAddressValid IP address

Example: 12.345.67.89
OpExists

Identity cookie exists
N/AValid IP address

Example: 12.345.67.89
OpNotExists

Identity Cookie does not exist
N/AValid IP address

Example: 12.345.67.89
OpIsDayOfWeek

Day of the week
DayOfWeekDay of the week

Example: U,0,1,2

- U = UTC time
- 0=Sun
- 1=Mon

Note: For local time, use L instead of U
OpLessThan

Date is less than the specified date
DateDate

Example: L,04/15/2019

- L=local time
- U=UTC
- Date in mm/dd/yyyy format
OpGreaterThan

Date is greater than the specified date
DateDate

Example: L,04/15/2019

- L=local time
- U=UTC
- Date in mm/dd/yyyy format
OpBetween

Range is in-between the specified dates
DateRangeDate 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
TimeTime

Example: L,11:00,12:00

- L=local Time
- U=UTC
- Time in hh:mm format
OpEqual

Equal to the defined condition
DeviceOsDevice OS level

Examples:

- iOS
- Android
- Windows
- Linux
- WindowsMobile
OpEqual

Equal to the defined condition
BrowserBrowser types

Examples:

- Other
- Chrome
- Firefox
- IE
- Safari
- MicrosoftEdge
OpEqual

Equal to the defined condition
RiskLevelRisk level

Examples:

- Normal - No risk detected
- Unknown - Undetermined risk
- Low
- Medium
- High
OpEqual

Equal to the defined condition
CountryCodeCountry code

Examples:

- SK - Slovakia
- US - United States
- etc
OpNotEqual

Not equal to the defined condition
DeviceOsDevice OS level

Examples:

- iOS
- Android
- Windows
- Linux
- WindowsMobile
OpNotEqual

Not equal to the defined condition
BrowserBrowser types

Examples:

- Other
- Chrome
- Firefox
- IE
- Safari
- MicrosoftEdge
OpNotEqual

Not equal to the defined condition
RiskLevelRisk level

Examples:

- Normal - No risk detected
- Unknown - Undetermined risk
- Low
- Medium
- High
OpNotEqual

Not equal to the defined condition
CountryCodeCountry 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 for AllowPersist. 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 ID ABC1234 forms tenant URL ABC1234.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

Authentication Cookies
Use your Tenant URL