Pre-Authentication
The pre-authentication
hook runs synchronously as part of a UI based login flow. The hook fires immediately after the user enters a username/email but before they enter their password or are prompted for multi-factor authentication.
Traditionally in OneLogin, what happens during the login flow is dictated by the User Policy that is assigned to a user. The primary benefit of this hook is that is gives you an opportunity to change the User Policy in real time based on a set of conditions.
For example, You may want to supress MFA registration unless a user is on a trusted network or prompt for stronger MFA factors when a user has a higher risk score or is travelling to a different country.
All of this is possible by creating the policies that represent the desired login behavior and then using the hook function to assign the appropriate policy at login time.
Minimum Viable Function
At a minimum the pre-authentication
hook should return a user object containing a policy_id
value. The function below is effectively like not having a pre-authentication
hook defined at all. It simply takes the user object from context and immediately returns it back to continue a login flow.
exports.handler = async (context) => {
return {
success: true,
user: {
policy_id: context.user.policy_id
}
}
}
This function must be base64 encoded and then is submitted to the create hook endpoint
{
"type": "pre-authentication",
"function": "",
"disabled": false,
"runtime": "nodejs18.x",
"retries": 0,
"timeout": 1,
"options": {
"risk_enabled": false,
"location_enabled": false,
"mfa_device_info_enabled": true
},
"env_vars": [
],
"packages": {
},
"conditions": [
{
"source": "roles",
"operator": "~",
"value": "123456"
}
]
}
Where hooks get exciting is when you consider what you might be able to do before returning the user and their associated user policy.
Hook Config Options
There are configuration options are specific to the Pre-Authentication hook. They allow you to control the information that is supplied to in the hook context which is useful for optimizing performance. Generally speaking every piece of context information comes at a cost to deliver so ideally you should only enable the context features that your hook is making of use of.
The following options can be supplied in the options
parameter when creating/updating a hook.
risk_enabled required boolean |
Default false. When true a risk score and risk reasons will be passed in the context. Only applies authentication time hooks. E.g. pre-authentication. |
mfa_device_info_enabled optional boolean |
Default false. When true a list of MFA devices registered by the user will be made available in the pre-authentication context. |
location_enabled required boolean |
Default false. When true an ip to location lookup is done and the location info is passed in the context. Only applies authentication time hooks. E.g. pre-authentication. |
Hook Context
A context object is passed into every hook function. The context contains information about the user and device as well as optional information about their current risk score and location.
To enable the continuous improvements and upgrades the context is versioned. With each version of the context some attributes may be added or removed so you should always check to see that your Smart Hook still functions as expected if you change the context version.
When creating a new pre-authentication hook the latest version of the context will be used. You can use prior context versions by specifying the context_version
attribute in your Smart Hook config.
Version 1.0.0
{
"user": {
"user_identifier": "jim-hendrix",
"policy_id": 187345
},
"device": {
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36",
"is_mobile": false
},
"location": {
"ip": "120.118.218.225",
"country_code": "TW"
},
"risk": {
"score": 30,
"reasons": [
"Infrequent access from 120.118.218.225",
"Infrequent access from Kaohsiung City, Kaohsiung, Taiwan",
"Infrequent access from Taiwan",
"Infrequent access using Chrome on Windows",
"Low trust for session"
]
},
"correlation_id": "13a97251-215d-4fa5-baaf-6fc15700a2db",
"request_id": "7d436b7e-b4a3-4b48-83fd-f4a12c22bb62"
}
Version 1.1.0
{
"user": {
"user_identifier": "jim-hendrix",
"policy_id": 187345,
"id": 36216766,
"last_login_success": "2020-10-21T17:04:22.852Z",
},
"device": {
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36",
"is_mobile": false
},
"location": {
"ip": "120.118.218.225",
"country_code": "TW"
},
"risk": {
"score": 30,
"reasons": [
"Infrequent access from 120.118.218.225",
"Infrequent access from Kaohsiung City, Kaohsiung, Taiwan",
"Infrequent access from Taiwan",
"Infrequent access using Chrome on Windows",
"Low trust for session"
]
},
"mfa_devices": [
{
"auth_factor_id" 16885,
"device_id" 1825100,
"user_display_name" "Google Authenticator",
"type_display_name" "Google Authenticator",
"auth_factor_name": "Google Authenticator",
"default": true,
"last_used_at": "2020-10-20T12:33:24.266Z",
"created_at": "2020-03-02T14:53:00.445Z"
}
],
"app": {,
"id: 959314,
"uuid": "1a650385-d500-42e3-921e-14aa4020ae70",
"name": "OIDC - PKCE",
},
"correlation_id": "13a97251-215d-4fa5-baaf-6fc15700a2db",
"request_id": "7d436b7e-b4a3-4b48-83fd-f4a12c22bb62"
}
Context Attributes
user |
An object that represents the user attempting to authenticate.
|
device |
An object describing the device used during the authentication.
|
location |
An object describing the location of the authenticating user. This is only populated if the location_enabled property is set to true when creating/updating the Hook function.
|
risk |
An object representing the current risk score for the authenticating user. This is only populated if the risk_enabled property is set to true when creating/updating the Hook function.
|
mfa_devices |
An object representing the mfa devices that are registered for the authenticating user. This is only populated if the mfa_device_info_enabled property is set to true when creating/updating the Hook function.
|
app |
An object representing the app that initiated the authentication. This attribute will be null for authentications that are not SP initiated. |
correlation_id |
A unique identifier that can be used to trace a transaction end to end. This is useful if you need help from OneLogin support in debugging any issues. |
request_id |
A unique identifier that can be used to trace a single incoming request. |
Hook Response
The Pre-authentication hook gives you the opportunity to change the User Policy that will be used for the rest of the login flow (it does not permanently change their assigned User Policy). Therefore the minimum required response for this hook is a user object containing the policy id.
For example, This function will do nothing and keep the User Policy set to the users currently allocated policy.
exports.handler = async (context) => {
return {
success: true,
user: {
policy_id: context.user.policy_id
}
}
}
Where as this hook function would change the User Policy for mobile device users
exports.handler = async (context) => {
let user = context.user;
if (context.device.is_mobile) {
user.policy_id = 1234;
}
return {
success: true,
user: user
}
}
You can also halt the login flow and therefore deny the user the ability to complete the login by returning success: false
from the function.
For example, Deny access based on high risk
exports.handler = async (context) => {
// Deny on high risk
if (context.risk.score > 90) return { success: false, user: null }
// Otherwise let them login as normal
return {
success: true,
user: context.user
}
}
Conditions
By default the Pre-Authentication Smart Hook will be executed for every UI based login. Conditions are an attribute the Smart Hook config that let you limit the number of users impacted by the hook via the use of Roles. This is particularly useful when developing and testing your hook but can also be used to further customize conditional access workflows.
For example, you might have thousands of users authenticating daily so you want to be careful when introducing a new hook. Rather than have the hook execute for every user login you could create a role called “Experimental Smart Hook Users” and then have the hook only trigger for users that are assigned to that role.
{
"type": "pre-authentication",
"conditions": [
{
"source": "roles",
"operator": "~",
"value": "123456"
}
]
}
source |
Must be set to roles. |
operator |
|
value |
The role_id to match on. |
Postman Collection
We’ve created a library of sample Hook functions in the Postman collection. We will keep it updated with functions that solve common requested workflows.
To view & modify the function click on the Pre Request Script
tab within Postman. Also note that this script will Base64 encode the function before it sends it to the Smart Hooks API.
- Clicking Run in Postman button navigates to the page where you can fork the collection to your workspace. Forking the collection into your workspace will enable you to contribute to the source collection using pull requests. You can also view the collection in a public workspace if you like and even import a copy of the collection using the links present on the screen.
Have a Question?
Found a problem or a bug? Submit a support ticket.
Looking for walkthroughs or how-to guides on OneLogin's user and admin features? Check out the documentation in our Knowledge Base.
Have a product idea or request? Share it with us in our Ideas Portal.