MFA for OAuth Clients
Centrify provides the ability to define challenge policies which can be used to perform multi-factor authentication (MFA) on behalf of a designated user (e.g. so OAuth clients can provide MFA).
This page describes the API workflows to programmatically create a challenge policy and use it in enabling MFA in an OAuth client.
Before continuing, ensure you are familiar with:
Creating a Challenge Policy
Step 1. Get the Roles
The first step is to get all roles by invoking the /RedRock/Query endpoint as shown here:
POST /RedRock/query
{
"Script":"Select *, COALESCE(Name, ID) AS DisplayName from Role ORDER BY DisplayName COLLATE NOCASE",
"Args":{
"PageNumber":1,
"PageSize":100000,
"Limit":100000,
"SortBy":"",
"direction":"False",
"Caching":-1
}
}
The Results
array contains information about each policy:
{
"success":true,
"Result":{
"IsAggregate":false,
"Count":57,
"Columns":[
{
"Name":"Description",
"IsHidden":false,
"DDName":"Description",
"Title":"Description",
"DDTitle":"Description",
"Description":null,
"Type":12,
"Format":null,
"Width":0,
"TableKey":"NotAKey",
"ForeignKey":null,
"TableName":"Role"
},
...
],
"FullCount":57,
"Results":[
{
"Entities":[
{
"Type":"Role",
"Key":"12332112_cea1_4fb6_80d7_de847c152d82",
"IsForeignKey":false
}
],
"Row":{
"ReadOnly":false,
"Description":null,
"DisplayName":"App Gateway Devs",
"DirectoryServiceUuid":"ABC12345-6CE8-465F-AB03-65766D33B05E",
"RoleType":"PrincipalList",
"_MatchFilter":null,
"Name":"App Gateway Devs",
"ID":"18240b41_cea1_4fb6_80d7_de847c152d82"
}
},
...
],
"ReturnID":""
},
"Message":null,
"MessageID":null,
"Exception":null,
"ErrorID":null,
"ErrorCode":null,
"InnerExceptions":null
}
Step 2. Determine if Cloud Mobile GP is being used.
The next step is determine if cloud mobile GP is enabled by invoking the /policy/GetUsingCloudMobileGP:
POST /policy/GetUsingCloudMobileGP
The useCloudGP
field indicates whether cloud GP is enabled:
{
"success":true,
"Result":{
"useCloudGP":true,
"useCloudCA":false,
"refreshInterval":15,
"gpUpdateInterval":300,
"activeDirectoryCA":"CA-CA1.centrify.com\\GLOBAL-CA2",
"cloudOuManagement":true,
"hasProxy":true,
"boundMobileForest":"centrify.com",
"hideMobilePolicyForAD":true
},
"Message":null,
"MessageID":null,
"Exception":null,
"ErrorID":null,
"ErrorCode":null,
"InnerExceptions":null
}
Step 3. Get the Plinks
Get information about each policy by invoking the /policy/getniceplinks endpoint:
POST /policy/getniceplinks
{
"Args":{
"PageNumber":1,
"PageSize":100000,
"Limit":100000,
"SortBy":"",
"direction":"False",
"Caching":-1
}
}
The Results
array contains information about each policy:
{
"success":true,
"Result":{
"Columns":[
{
"Name":"Params",
"IsHidden":false,
"DDName":null,
"Title":"Params",
"DDTitle":null,
"Description":null,
"Type":16,
"Format":null,
"Width":0,
"TableKey":null,
"ForeignKey":null,
"TableName":null
},
...
],
"RevStamp":"636537274890000000",
"Count":28,
"Results":[
{
"Entities":[
{
"Type":"PolicyLink",
"Key":"/Policy/Default Policy",
"IsForeignKey":false
}
],
"Row":{
"Params":[
],
"ID":"/Policy/Default Policy",
"EnableCompliant":true,
"I18NDescriptionTag":"_I18N_DefaultGlobalPolicyDescriptionTag",
"Description":"DO NOT DISABLE Login MFA IN THIS POLICY for unknown devices.",
"LinkType":"Global",
"PolicySet":"/Policy/Default Policy"
}
},
...
],
"FullCount":28,
"ReturnID":"",
"IsAggregate":false
},
"Message":null,
"MessageID":null,
"Exception":null,
"ErrorID":null,
"ErrorCode":null,
"InnerExceptions":null
}
Step 4. Get the Policy Block
Using the policies returned in the previous response, determine the policy that you want to add a challenge policy to, and then invoke the /Policy/getpolicyblock endpoint, passing the ID via the name
field in the body:
POST /policy/getpolicyblock
{
"name":"/Policy/Default Policy"
}
The response contains information about the policy:
{
"success":true,
"Result":{
"Description":"DO NOT DISABLE Login MFA IN THIS POLICY for unknown devices.",
"PolicyModifiers":[
],
"Settings":{
"/Mobile/Software/Policies/Centrify/Common/AllowNotificationOnMutipleDevices":true,
"/Core/Authentication/IwaSatisfiesAllMechs":false,
"/Core/Authentication/SecurityQuestionAnswerMinLength":3,
"/Core/Authentication/IwaSetKnownEndpoint":true,
"/Core/MfaRestrictions/BlockMobileMechsOnMobileLogin":false,
"/Core/PasswordReset/AccountUnlockAuthProfile":"e4eeeeee-2e9e-4567-b9e2-a568360c8eb7",
"/Core/Authentication/ZsoSatisfiesAllMechs":false,
"/Core/Authentication/AdminSecurityQuestionsPerUser":0,
"/Core/Security/CDS/ExternalMFA/ShowQRCodeForSelfService":true,
"/Core/Authentication/ChallengeDefinitionId":"0d799995-ca79-43df-9355-fdf12394965b",
"/Core/Authentication/ZsoSetKnownEndpoint":true,
"PasswordResetEnabled":true,
"/Mobile/Software/Policies/Centrify/Common/Restrictions/TrackLocationHistory":true,
"/Core/PasswordReset/Max":10,
"/Core/PasswordReset/PasswordResetADEnabled":true,
"/Mobile/EnrollRules/Common/AllowJailBrokenDevices":true,
"/Core/PasswordReset/PasswordResetIdentityCookieOnly":false,
"/Core/Security/CDS/LockoutPolicy/Threshold":5,
"/Core/PasswordReset/UseADAdmin":false,
"AuthenticationEnabled":true,
"/Core/PasswordReset/MaxTime":60,
"/Core/PasswordReset/PasswordResetEnabled":true,
"/Mobile/DeviceManagement/UseCentrifyAsMdm":false,
"/Core/Security/CDS/ExternalMFA/UiPrompt":"OATH OTP Client",
"/Core/Authentication/AuthenticationRules":{
"_UniqueKey":"Condition",
"_Value":[
{
"Conditions":[
{
"Prop":"IdentityCookie",
"Op":"OpExists"
}
],
"ProfileId":"44bd658e-defc-4d69-b6de-3dc0d6812f9b"
}
],
"Enabled":true,
"_Type":"RowSet"
},
"/Core/Security/CDS/ExternalMFA/ShowQRCode":true,
"/Core/Authentication/AuthenticationRulesDefaultProfileId":"cfefffff-9bf7-4569-895d-9dfbb3a9e8d7",
"/Core/PasswordReset/PasswordResetAuthProfile":"a7dddddd-fe4e-4f37-a885-2176beb4a501",
"/Mobile/EnrollRules/Common/AllowEnrollment":true,
"/Core/Authentication/ConfigureSecurityQuestions":true,
"/Core/PasswordReset/AccountUnlockADEnabled":false,
"/Core/Authentication/UserSecurityQuestionsPerUser":1,
"/Core/Authentication/CookieAllowPersist":false,
"/Core/PasswordReset/AccountUnlockEnabled":true,
"/Core/Authentication/AuthenticationRulesHighAuthRequestedProfileId":"12222222-9aad-4e49-8e23-1e4561d9b7c3",
"/Core/PasswordReset/AccountUnlockIdentityCookieOnly":false,
"/Core/Authentication/NoMfaMechLogin":false,
"/Core/Authentication/AllowIwa":true,
"/Core/Authentication/AllowZso":true
},
"Path":"/Policy/Default Policy",
"RiskAnalysisLevels":{
"Levels":[
{
"Name":"Normal",
"TranslatedName":"None Detected"
},
{
"Name":"Low",
"TranslatedName":"Low"
},
{
"Name":"Med",
"TranslatedName":"Medium"
},
{
"Name":"High",
"TranslatedName":"High"
},
{
"Name":"Unknown",
"TranslatedName":"Undetermined"
}
]
},
"AuthProfiles":[
{
"Uuid":"12222222-9aad-4e49-8e23-1e4561d9b7c3",
"Name":"Default New Device Login Profile",
"DurationInMinutes":720,
"Challenges":[
"UP"
],
"AdditionalData":{
}
},
{
"Uuid":"a7dddddd-fe4e-4f37-a885-2176beb4a501",
"Name":"Default Password Reset Profile",
"DurationInMinutes":720,
"Challenges":[
"OTP,SMS,EMAIL,OATH"
],
"AdditionalData":{
}
},
...
],
"RevStamp":"636486318310000000",
"Version":6
},
"Message":null,
"MessageID":null,
"Exception":null,
"ErrorID":null,
"ErrorCode":null,
"InnerExceptions":null
}
Step 5. Add the Challenge Policy
Add a challenge policy by invoking the /Policy/AddAuthPolicyModifier endpoint, setting the PolicyModifier
body parameter to the name of the new challenge policy:
POST /Policy/AddAuthPolicyModifier
{
"PolicyModifier":"test1"
}
The success
field in the response indicates if the request was successful:
{
"success":true,
"Result":null,
"Message":null,
"MessageID":null,
"Exception":null,
"ErrorID":null,
"ErrorCode":null,
"InnerExceptions":null
}
Step 6. Save the Policy Block
Save the policy block by invoking the /policy/savepolicyblock3 endpoint and passing the information returned in the response to the /policy/getpolicyblock
above:
POST /policy/savepolicyblock3
{
"policy":{
"Description":"DO NOT DISABLE Login MFA IN THIS POLICY for unknown devices.",
"PolicyModifiers":[
],
"Settings":{
"/Mobile/Software/Policies/Centrify/Common/AllowNotificationOnMutipleDevices":true,
"/Core/Authentication/IwaSatisfiesAllMechs":false,
"/Core/Authentication/SecurityQuestionAnswerMinLength":3,
"/Core/Authentication/IwaSetKnownEndpoint":true,
"/Core/MfaRestrictions/BlockMobileMechsOnMobileLogin":false,
"/Core/PasswordReset/AccountUnlockAuthProfile":"e4eeeeee-2e9e-4567-b9e2-a568360c8eb7",
"/Core/Authentication/ZsoSatisfiesAllMechs":false,
"/Core/Authentication/AdminSecurityQuestionsPerUser":0,
"/Core/Security/CDS/ExternalMFA/ShowQRCodeForSelfService":true,
"/Core/Authentication/ChallengeDefinitionId":"0d799995-ca79-43df-9355-fdf12394965b",
"/Core/Authentication/ZsoSetKnownEndpoint":true,
"PasswordResetEnabled":true,
"/Mobile/Software/Policies/Centrify/Common/Restrictions/TrackLocationHistory":true,
"/Core/PasswordReset/Max":10,
"/Core/PasswordReset/PasswordResetADEnabled":true,
"/Mobile/EnrollRules/Common/AllowJailBrokenDevices":true,
"/Core/PasswordReset/PasswordResetIdentityCookieOnly":false,
"/Core/Security/CDS/LockoutPolicy/Threshold":5,
"/Core/PasswordReset/UseADAdmin":false,
"AuthenticationEnabled":true,
"/Core/PasswordReset/MaxTime":60,
"/Core/PasswordReset/PasswordResetEnabled":true,
"/Mobile/DeviceManagement/UseCentrifyAsMdm":false,
"/Core/Security/CDS/ExternalMFA/UiPrompt":"OATH OTP Client",
"/Core/Authentication/AuthenticationRules":{
"_UniqueKey":"Condition",
"_Value":[
{
"Conditions":[
{
"Prop":"IdentityCookie",
"Op":"OpExists"
}
],
"ProfileId":"44bd658e-defc-4d69-b6de-3dc0d6812f9b"
}
],
"Enabled":true,
"_Type":"RowSet"
},
"/Core/Security/CDS/ExternalMFA/ShowQRCode":true,
"/Core/Authentication/AuthenticationRulesDefaultProfileId":"cfea9de5-9bf7-4569-895d-9dfbb3a9e8d7",
"/Core/PasswordReset/PasswordResetAuthProfile":"a7dddddd-fe4e-4f37-a885-2176beb4a501",
"/Mobile/EnrollRules/Common/AllowEnrollment":true,
"/Core/Authentication/ConfigureSecurityQuestions":true,
"/Core/PasswordReset/AccountUnlockADEnabled":false,
"/Core/Authentication/UserSecurityQuestionsPerUser":1,
"/Core/Authentication/CookieAllowPersist":false,
"/Core/PasswordReset/AccountUnlockEnabled":true,
"/Core/Authentication/AuthenticationRulesHighAuthRequestedProfileId":"12222222-9aad-4e49-8e23-1e4561d9b7c3",
"/Core/PasswordReset/AccountUnlockIdentityCookieOnly":false,
"/Core/Authentication/NoMfaMechLogin":false,
"/Core/Authentication/AllowIwa":true,
"/Core/Authentication/AllowZso":true,
"/Core/test1/AuthenticationEnabled":true,
"/Core/test1/Authentication/AuthenticationRules":{
"_Type":"RowSet",
"Enabled":true,
"_UniqueKey":"Condition",
"_Value":[
{
"Conditions":[
{
"Prop":"DateRange",
"Op":"OpBetween",
"Val":"L,02/23/2018,02/28/2018"
}
],
"ProfileId":"cfea9de5-9bf7-4569-895d-9dfbb3a9e8d7"
}
]
},
"/Core/test1/Authentication/AuthenticationRulesDefaultProfileId":"cfefffff-9bf7-4569-895d-9dfbb3a9e8d7",
"/Core/test1/Authentication/NoMfaMechLogin":false
},
"Path":"/Policy/Default Policy",
"RiskAnalysisLevels":{
"Levels":[
{
"Name":"Normal",
"TranslatedName":"None Detected"
},
{
"Name":"Low",
"TranslatedName":"Low"
},
{
"Name":"Med",
"TranslatedName":"Medium"
},
{
"Name":"High",
"TranslatedName":"High"
},
{
"Name":"Unknown",
"TranslatedName":"Undetermined"
}
]
},
"AuthProfiles":[
{
"Uuid":"122f46ae-9aad-4e49-8e23-1e4561d9b7c3",
"Name":"Default New Device Login Profile",
"DurationInMinutes":720,
"Challenges":[
"UP"
],
"AdditionalData":{
}
},
...
],
"RevStamp":"636486318310000000",
"Version":6,
"Newpolicy":false
},
"plinks":[
{
"Params":[
"Device|@Active Devices"
],
"ID":"/Policy/louie1",
"EnableCompliant":true,
"Description":"",
"LinkType":"Collection",
"PolicySet":"/Policy/louie1"
},
{
"Params":[
"52577777_7f2f_4654_97f5_3123dfc5d5c7"
],
"ID":"/Policy/RichPolicy",
"EnableCompliant":true,
"Description":"",
"LinkType":"Role",
"PolicySet":"/Policy/RichPolicy"
},
{
"Params":[
"8a666666_ec81_4f52_86b7_9377d49c217b"
],
"ID":"/Policy/U2F Login Policy",
"EnableCompliant":true,
"Description":"",
"LinkType":"Role",
"PolicySet":"/Policy/U2F Login Policy"
},
...
]
}
The success
field in the response indicates if the request was successful and the RevStamp
field indicates the revision of the new policy block that was created:
{
"success":true,
"Result":{
"RevStamp":"636549980660000000"
},
"Message":null,
"MessageID":null,
"Exception":null,
"ErrorID":null,
"ErrorCode":null,
"InnerExceptions":null
}
Using the Challenge for MFA in an OAuth Client
Step 1. Start the Authentication
Start the normal authentication process by invoking the /security/startauthentication endpoint:
POST /security/startauthentication
{
"User": "[email protected]",
"Version": "1.0"
}
The response contains authentication challenges:
{
"success":true,
"Result":{
"ClientHints":{
"PersistDefault":false,
"AllowPersist":false,
"AllowForgotPassword":true
},
"Version":"1.0",
"SessionId":"N_XRw-zRM0GUZOA8vdOnWnT...",
"Challenges":[
{
"Mechanisms":[
{
"AnswerType":"Text",
"Name":"UP",
"PromptMechChosen":"Enter Password",
"PromptSelectMech":"Password",
"MechanismId":"nOt4E8G9rUybPu_ph4t..."
}
]
}
],
"Summary":"NewPackage",
"TenantId":"AAA1234"
},
"Message":null,
"MessageID":null,
"Exception":null,
"ErrorID":null,
"ErrorCode":null,
"InnerExceptions":null
}
Step 2. Advance the Authentication
Invoke the /security/advanceauthentication endpoint for each challenge. In this example a password is being provided for a password challenge:
POST /security/advanceauthentication
{
"MechanismId": "nOt4E8G9rUybPu_ph4tTG-0P...",
"Answer": "abcd1234",
"SessionId": "N_XRw-zRM0GUZOA8vdOnW...",
"TenantId": "AAA1234",
"PersistentLogin": false,
"Action": "Answer"
}
The success
field in the response indicates if the request was successful:
{
"success":true,
"Result":{
"SystemID":"AAA1234",
"DisplayName":"J N",
"EmailAddress":"[email protected]",
"CustomerID":"AAA1234",
"AuthLevel":"Normal",
"PodFqdn":"corp.my-dev.centrify.com",
"Auth":"F67AFC...",
"User":"[email protected]",
"UserDirectory":"AdProxy",
"Summary":"LoginSuccess",
"UserId":"128cadec-b5f5-4995-a5...",
"SourceDsType":"AdProxy"
},
"Message":null,
"MessageID":null,
"Exception":null,
"ErrorID":null,
"ErrorCode":null,
"InnerExceptions":null
}
Step 3. Start the Application
Invoke the endpoint corresponding to your application. Construct the endpoint URL by concatenating /token/ and the name of your application, and then pass the application-specific parameters as a text string in the body:
POST /oauth2/token/_genericmfa
scope=GenericMFA&grant_type=client_credentials
The response contains application-specific information. In the example below, the access_token
field contains a new access token to use in the next request:
{
"access_token":"eyJhb...",
"token_type":"Bearer",
"expires_in":31536000,
"scope":"GenericMFA"
}
Step 4. Specify the Challenge Policy
Invoke the /security/OnDemandChallenge endpoint specifying the name of the user to authenticate on behalf of in the User
field, and the name of the challenge policy in the PolicyModifier
field:
POST /security/OnDemandChallenge
{
"User": "[email protected]",
"arguments": null,
"PolicyModifier": "test1"
}
Note: the on-demand challenge only works with the Client Credentials Flow.
The response contains the set of challenges associated with that challenge policy. In the example below, there are two challenges: a password challenge and an Oob verification code challenge which can be sent either by email or SMS:
{
"success":true,
"Result":{
"ClientHints":{
"PersistDefault":false,
"AllowPersist":false,
"AllowForgotPassword":true
},
"Version":"1.0",
"SessionId":"-AW5S9HtHGv...",
"Challenges":[
{
"Mechanisms":[
{
"AnswerType":"Text",
"Name":"UP",
"PromptMechChosen":"Enter Password",
"PromptSelectMech":"Password",
"MechanismId":"UFx-ivi..."
}
]
},
{
"Mechanisms":[
{
"AnswerType":"StartTextOob",
"Name":"EMAIL",
"PromptMechChosen":"Click the link in the email sent to [email protected]",
"PromptSelectMech":"Email... @centrify.com",
"PartialAddress":"centrify.com",
"MechanismId":"UuWMQ3CAoU..."
},
{
"AnswerType":"StartTextOob",
"Name":"SMS",
"PartialDeviceAddress":"4660",
"PromptMechChosen":"Sending a text to mobile phone ending... 4660. Enter the code or click the link in the message to proceed with authentication.",
"PromptSelectMech":"SMS... XXX-1234",
"MechanismId":"oTE_Oxjdqk..."
}
]
}
],
"Summary":"NewPackage",
"TenantId":"AAA1234"
},
"Message":null,
"MessageID":null,
"Exception":null,
"ErrorID":null,
"ErrorCode":null,
"InnerExceptions":null
}
Step 5. Advance the Authentication on Behalf of the User
Invoke the /security/advanceauthentication
endpoint for each of the challenges returned from the /security/OnDemandChallenge
endpoint.
The following example provides the password for the first challenge:
POST /security/advanceauthentication
{
"MechanismId": "UFx-iviXi_EoET50...",
"Answer": "123abcd",
"SessionId": "-AW5S9HtHGv5NK...",
"TenantId": "AAA1234",
"PersistentLogin": false,
"Action": "Answer"
}
The Summary
field in the response indicates that the next challenge is to be started:
{
"success":true,
"Result":{
"Summary":"StartNextChallenge"
},
"Message":null,
"MessageID":null,
"Exception":null,
"ErrorID":null,
"ErrorCode":null,
"InnerExceptions":null
}
The next example starts the Oob challenge to send a verification code to the user's device via SMS:
POST /security/advanceauthentication
{
"TenantId": "AAA1234",
"MechanismId": "oTE_OxjdqkGR...",
"PersistentLogin": false,
"Action": "StartOOB",
"SessionId": "-AW5S9HtHGv5NKIfG..."
}
The Summary
field in the response indicates that the Oob verification code has been sent and that Centrify is waiting for the user to provide that code:
{
"success":true,
"Result":{
"Summary":"OobPending"
},
"Message":null,
"MessageID":null,
"Exception":null,
"ErrorID":null,
"ErrorCode":null,
"InnerExceptions":null
}
In the final example below, the code is sent to Centrify via the Answer
field:
POST /security/advanceauthentication
{
"MechanismId": "oTE_OxjdqkGRzbQPdIPvG4A...",
"Action": "Answer",
"SessionId": "-AW5S9HtHGv5NKIfGA3...",
"Answer": "123456789",
"TenantId": "AAA1234",
"PersistentLogin": false
}
The success
field in the response indicates that the challenge was successfully fulfilled:
{
"success":true,
"Result":{
"SystemID":"AAA1234",
"DisplayName":"J N",
"EmailAddress":"[email protected]",
"CustomerID":"AAA1234",
"AuthLevel":"High",
"PodFqdn":"corp.my-dev.centrify.com",
"User":"[email protected]",
"UserDirectory":"AdProxy",
"Summary":"LoginSuccess",
"UserId":"128cadec-b5f5-49...7",
"SourceDsType":"AdProxy"
},
"Message":null,
"MessageID":null,
"Exception":null,
"ErrorID":null,
"ErrorCode":null,
"InnerExceptions":null
}
The client has now successfully logged the user in using MFA from a challenge policy.
Try the API in Postman:
.
Click here for help with using our sample Postman collection.
Updated over 4 years ago