Skip to main content

New User Authentication API

These API calls are only supported for organizations that are integrated with Active Directory. It will perform just-in-time user provisioning for users that don't have an existing Arculix account.

Note

For an overview of the Authentication API, including a glossary of terms and prerequisites, see Authentication API.

Authenticating to the API

This REST API uses the OAuth client_credentials authentication flow.

Get Access Token from the authorization endpoint (/oauth/token)

Note

This API requires a public scope.

The client_id and client_secret must match the ID and secret of the application the user is attempting to access. Additionally, the same token should be used for all requests to the API endpoint for the same user authentication event.

Parameter

Type

Description

grant_type

String

client_credentials. Indicates the desired OAuth flow

client_id

String

The UID of the calling application in Arculix

client_secret

String

The client secret for the application in Arculix

scope

String

A space-delimited list of scopes to be issued to the access token

This API requires a public scope.

Sample request

{
   "grant_type": "client_credentials",
   "client_id": "YOUR_ARCULIX_APPLICATION_UID",
   "client_secret": "YOUR_ARCULIX_APPLICATION_SECRET",
   "scope": "public"
}

This will return the access token if that application is authorized with the requested scopes.

Note

The generated access tokens are more than 255 bytes in length, so when storing them make sure to have at least 500 bytes of storage available or else they will be truncated.

Sample response

{
   "access_token": "YOUR_OAUTH_ACCESS_TOKEN",
   "token_type": "Bearer",
   "expires_in": 7200,
   "scope": "public",
   "created_at": 1630710187
}

Call API endpoint, sending the access token in the Authorization HTTP header with Bearer:

Authorization: Bearer YOUR_OAUTH_ACCESS_TOKEN

Authenticate a User

Initiate a user authentication flow.

Header

Field

Type

Description

Accept-Language

String

Preferred language for user-facing messages.

Default value: en

HTTP-X-ACCEPTTO-RISK-ENGINE optional

json

JSON string that will be passed to the risk engine and will be available as authentication_context.http_header_params.

Note that the name of the parameter might vary based on your deployment configuration. (Setting.risk_engine_http_header_parameter).

Request

Method

URL

POST

/api/integration/v2/authn

Parameters

Field

Type

Description

credential_type

String

Type of authentication/authorization. Users will see this value as the event type in the mobile app and elsewhere unless a type parameter is specified

Allowed values: "password_login" , "password_less_login" , "qr_login".

auth_credentials

Object

The credential that will be used for authentication.

Internal schema of auth_credentialsdepends on the credential_type parameter.

For more information, see sample requests.

session_uid optional

String

A unique identifier for the session. This is the unique value that the relying party should generate for the lifetime of a session and should be unique across the relying party organization between different applications.

message optional

String

Message that user receives using push notification on Arculix Mobile app or via text/voice message.

type optional

String

Type of authentication/authorization. User will see this value as the type of transaction on mobile app.

For example: Login , Payment.

auth_factor optional

String

Array of strings identifying preferred out of band method to be automatically sent to the user (currently only supports first item).

The possible values are: push , sms , email , voice .

timeout optional

Integer

The timeout value for the authentication request in seconds; if the user does not respond within the specified time, the request expires.

The default value is 300 seconds (5 minutes).

ip_address optional

String

The end user's IP address, to be used for policy-based risk assessment and logging.

remote_ip_address optional

String

End user's remote ip address (IP behind proxy) for enabling IP based policies and logging.

totp optional

String

Users can be authenticated via TOTP by allowing them to enter their time based one-time passcodes while signing in.

When TOTP is specified and is correct, the status of the response is approved.

If the TOTP is incorrect, the authentication request will be rejected and no other MFA method will be offered.

bfpToken optional

String

The value of the Arculix DBFP cookie, if in use.

response_format optional

String

Requested response format.

Default value: json.

Allowed values: "json" , "jwt".

Sample request

{
    "credential_type": "password_less_login",
    "auth_credentials": {
        "username": "abe.lincoln"
    },
    "type": "BillPayment",
    "auth_factor": [
        "push"
    ],
    "bfpToken": "a6a5effa4d8c6xxxx123efed89033ab70ae"
}

Response

Successful response

Field

Type

Description

success

Boolean

Shows whether operation was successful or not.

response_code

String

Returns response code of success.

status

String

Shows status of MFA.

The possible values are: pending , expired, approved , rejected.

session_uid

String

A unique identifier for the session. This is the unique value that the relying party should generate for the lifetime of a session and should be unique across the relying party organization between different applications.

user_email

String

Email address of the user that is authenticating.

auth_options

Array

Allowed authentication methods for the MFA step.

The possible values are: push , sms , email , voice , totp.

expires_at

String

Shows expiry time of MFA in ISO 8601 format.

notification_type

String

The type of notification that has been sent to the user, if any.

Successful response example

HTTP/1.1 200 OK

{
    "success": true,
    "response_code": "success",
    "channel": "1556910423f49963ade2d1951359b1fe15fcd72c41",
    "status": "approved/pending/rejected",
    "session_uid": 10037,
    "user_email": "abe.lincoln@mailinator.com",
    "auth_options": ["push", "totp"],
    "expires_at": "2020-02-11T10:23:57-08:00",
    "notification_type": null
}

Unsuccessful response

Error

Field

Type

Description

response_code

String

Normalized response code describing the error type.

success

String

Generally false.

message

String

Informative message describing the error.

Response codes

Field

Type

Description

Response example

no_authenticator_found

String

No authenticator with the specified type found for the organization.

HTTP/1.1 422 Unprocessable Entity

{
  "content": {
    "response_code": "no_authenticator_found",
    "success": false,
    "message": "Something went wrong, Please contact support@secureauth.com for further assistance."
  }
}

generic_error

String

If anything else goes wrong, such as a missing parameter or invalid JWT, then a general error message is returned

HTTP/1.1 4XX OK

{
  "response_code": "generic_error",
  "success": false,
  "message": "error message"
}

Send Out of Band

Send out of band MFA request to user.

Header

Field

Type

Description

Accept-Language

String

Preferred language for user-facing messages.

Default value: en

Request

Method

URL

POST

/api/integration/v2/authn/{channel}/factors/{type}/send

Parameters

Field

Type

Description

type

String

Out of band method to be sent to user.

Allowed values: "push" , "sms" , "email" , "voice".

response_format optional

String

Requested response format.

Default value: json.

Allowed values: "json" , "jwt".

channel

String

The channel returned from a successful authentication request, uniquely identifying the MFA transaction.

Response

Successful response

Field

Type

Description

response_code

String

Returns response code.

The possible values are: push_sent , sms_sent , email_sent , voice_sent.

success

Boolean

Shows whether operation was successful or not.

status

String

Shows status of MFA.

The possible values are: pending , expired, approved , rejected.

expires_at

String

Shows expiry time of MFA in ISO 8601 format.

notification_type

String

Notification type sent to user.

The possible values are: sms , email , call , push.

message

String

Message that can be shown to end-user.

Successful response example

HTTP/1.1 200 OK

{
    "response_code": "[otp_type]_sent",
    "success": true,
    "status": "pending",
    "expires_at": "2020-02-11T10:23:57-08:00",
    "notification_type": "sms/email/call/push",
    "message": "We just sent you a 6-digit passcode, please check your SMS inbox."
}

Unsuccessful response

Error

Field

Type

Description

response_code

String

Normalized response code describing the error type.

success

String

Generally false.

message

String

Informative message describing the error.

Response codes

Field

Type

Description

Response example

mfa_invalid_state

String

Authentication request is no longer valid, no OOB sent.

HTTP/1.1 200 OK

{
  "content": {
    "response_code": "mfa_invalid_state",
    "success": false,
    "message": "Your authentication request is no longer valid, please try to login again.",
    "expires_at": "2020-02-11T10:23:57-08:00",
    "notification_type": "sms/email/voice",
    "status": "expired/rejected/approved"
  }
}

not_allowed

String

Authentication method not allowed for this application and user.

HTTP/1.1 200 OK

{
  "content": {
    "response_code": "not_allowed",
    "success": false,
    "message": "Authentication method is not allowed for this application and user!",
    "expires_at": "2020-02-11T10:23:57-08:00",
    "notification_type": null,
    "status": "pending"
  }
}

wait_for_resend

String

Must wait to re-send OOB notification.

HTTP/1.1 200 OK

{
  "content": {
    "response_code": "wait_for_resend",
    "success": false,
    "message": "MFA request rate exceeded. Please wait 22 seconds before requesting a new sms.",
    "expires_at": "2020-02-11T10:23:57-08:00",
    "notification_type": "sms",
    "status": "pending"
  }
}

tfa_not_found

String

No TFA with the given channel found for this application.

HTTP/1.1 404 Not Found

{
  "content": {
    "response_code": "tfa_not_found",
    "success": false,
    "message": "No authentication request found for this user with the specified channel.",
  }
}

Verify Factor

Verifies the credential of the chosen authentication factor type.

Header

Field

Type

Description

Accept-Language

String

Preferred language for user-facing messages.

Default value: en.

Request

Method

URL

POST

/api/integration/v2/authn/{channel}/factors/{type}/verify

Parameters

Field

Type

Description

type

String

Factor type being verified.

Allowed values: "sms" , "email" , "voice" , "totp".

response_format optional

String

Requested response format.

Default value: json.

Allowed values: "json" , "jwt".

channel

String

The channel returned from a successful authentication request, uniquely identifying the MFA transaction.

Request body

Field

Type

Description

factor_response

Object

Object with factor verifier details.

factor_response.code optional

String

Authentication factor code.

This is the passcode entered by the user to verify the MFA.

Sample request

{
    "factor_response": {
        "code": "123456"
    }
}

Response

Successful response

Field

Type

Description

success

Boolean

Shows whether the API call was successful or not.

response_code

String

Returns response code of success.

status

String

Shows status of MFA.

The possible values are: pending , expired, approved , rejected.

message

String

Message that explains success.

retry_attempts_remaining

Integer

The number of attempts remaining to verify factor.

Successful response example
HTTP/1.1 200 OK

{
    "response_code": "success",
    "success": true,
    "status": "approved",
    "message": "Your Authorization Request Was Successful!",
    "retry_attempts_remaining": 3
}

Unsuccessful response

Error

Field

Type

Description

response_code

String

Normalized response code describing the error type.

success

String

Generally false.

message

String

Informative message describing the error.

Response codes

Field

Type

Description

Response example

mfa_invalid_state

String

Authentication request is no longer valid, or OTP not checked.

HTTP/1.1 200 OK

{
    "response_code": "mfa_invalid_state",
    "success": false,
    "message": "Your authentication request is no longer valid, please try to login again.",
    "status": "expired/rejected/approved"
}

invalid_otp

String

Invalid passcode specified.

HTTP/1.1 200 OK

{
    "response_code":"invalid_otp",
    "success": false,
    "message":"Invalid passcode was specified, please try again!",
    "status": "pending",
    "retry_attempts_remaining": 2
}

max_retry

String

OTP is invalid and the number of max attempts has been exceeded.

TFA is automatically rejected.

HTTP/1.1 200 OK

{
    "response_code": "max_retry",
    "success": false,
    "message":"Maximum PIN attempts exceeded. Authorization request denied.",
    "status": "rejected",
    "retry_attempts_remaining": 0
}

tfa_not_found

String

No TFA with the given channel found for this application.

HTTP/1.1 404 Not Found

{
    "response_code": "tfa_not_found",
    "success": false,
    "message": "No authentication request found for this user with the specified channel.",
}

Status

Checks and returns authentication result status based on channel.

Header

Field

Type

Description

Accept-Language

String

Preferred language for user-facing messages.

Default value: en.

Request

Method

URL

GET

/api/integration/v2/authn/{channel}/status

Parameters

Field

Type

Description

channel

String

The channel returned from a successful authentication request, uniquely identifying the MFA transaction.

response_format optional

String

Requested response format.

Default value: json.

Allowed values: "json" , "jwt".

Response

Successful response

Field

Type

Description

success

Boolean

Whether the API call was successful or not.

response_code

String

Normalized response code describing the error type or "success".

status

String

Shows status of MFA, possible values pending/expired/approved/rejected.

channel

String

The channel uniquely identifying the TFA.

user_id

String

Internal user ID.

expires_at

String

The TFA expiry in ISO 8601 format.

session_uid

String

Unique user session identifier.

Successful response example

HTTP/1.1 200 OK

{
    "success": true,
    "response_code": "success",
    "status": "approved/pending/rejected",
    "channel": "1556910423f49963ade2d1951359b1fe15fcd72c41",
    "user_id": 3891,
    "expires_at": "2020-02-11T10:23:57-08:00",
    "session_uid": "aea7f1d0dd368e448e92ac30a5d8e34d"
}

Unsuccessful response

Error

Field

Type

Description

response_code

String

Normalized response code describing the error type.

success

String

Generally false.

message

String

Informative message describing the error.

Response codes

Field

Type

Description

Response example

tfa_not_found

String

No TFA with the given channel found for this application.

HTTP/1.1 404 Not Found

{
  "content": {
    "response_code": "tfa_not_found",
    "success": false,
    "message": "No authentication request found for this user with the specified channel.",
  }
}

OAuth calculate LOA score (Risk Engine)

If your organization and relying party application both have access to a standalone risk engine license, the relying party application can submit raw request information to the Arculix API to calculate the LOA score for the current session.

To calculate the LOA score, it takes user data from the history and normality of user behavior, and from other sources like AI/ML engine, user browser fingerprint, geolocation, and so on. You can use this API for continuous authentication, enabling the Arculix risk engine to calculate the LOA score based on changes to the current session and context to the existing request.

For example, during a user session, a change in the IP address, browser fingerprint, or GPS location can impact the LOA score in a current session. You can also use the API to send data to the risk engine from native or web applications that do not have a direct integration with the Arculix Mobile SDK or a single sign-on solution.

Note

For the OAuth calculate LOA score API to work, the application must have permission to send data to the risk_engine.

Request

Method

URL

POST

/api/integration/v2/risk_engine/calculate_score

Parameters

Field

Type

Description

email

String

User's email address.

Email domain should belong to the organization.

session_uid

String

A unique identifier for the session.

This is the unique value that the relying party should generate for the lifetime of a session and should be unique across the relying party organization between different applications.

event

String

The authentication event; possible values are pre-auth, authpost-auth, and cont-auth (continuous authentication).

context

JSON

The context of the authentication request should contain all the key/values the relying party has from the user’s request.

Depending on the keys present in this parameter, the Arculix risk engine decides which risk analyzers it must engage in calculating the final LOA score.

For the list of possible key-value pairs, see the Context section.

Note

If you want the risk engine to mark the provided data, like IP, location, and DBFP as trusted for future MFAs, use post-auth for the value of the event key. Otherwise, it will discard data from all other events.

Context

The Arculix risk engine captures and stores any key/value sent to this API. But, certain keys have special meanings used by existing risk analyzers to calculate the LOA score for the request. The following is a list of keys and corresponding risk analyzers that are looking for the key in context.

Key

Description

Risk Analyzer

ip_address

The public IP address of the end user.

IP Risk Analyzer

latitude

The GeolocationCoordinates.latitude property is a double-precision floating point value which represents the latitude of a geographical position, specified in decimal degrees.

Location Risk Analyzer

longitude

The GeolocationCoordinates.longitude property is a double-precision floating point value which represents the longitude of a geographical position, specified in decimal degrees.

Location Risk Analyzer

accuracy

The GeolocationCoordinates.accuracy attribute denotes the accuracy level of the latitude and longitude coordinates in meters (such as 65 meters).

Arculix will discard the geolocation information if accuracy is above a certain threshold. By default this number is 100 and it will discard any data with accuracy above 100.

Location Risk Analyzer

bfpToken

When integrating with the Arculix DBFP JavaScript plugin, the device and browser fingerprints (DBFP) engine will create a cookie named jwt cookie.

The value of this cookie should be passed as bfpToken to the risk engine.

DBFP Risk Analyzer

user_agent

A characteristic string that enables servers and network peers to identify the application, operating system, vendor, or version of the requesting user agent.

DBFP Risk Analyzer

oob_name

Out-of-band method used during authentication. Supported values are: 

pushfido_pushtotpsmsemailvoicefido_u2fsecurity_questionpolicystatic_pinexternal_oob.

Auth Method Risk Analyzer

mobile_device.device_uuid

A universally unique mobile device identifier if the data is coming from a native mobile application.

Device Trust

mobile_device.device_type

Model information of the mobile device. For example, iPhone 11.

Device Trust

mobile_device.app_version

Native mobile application version number that is sending the information.

Device Trust

mobile_device.os_type

Mobile device operating system. For example, iOS or Android.

Device Trust

mobile_device.os_version

Operating system version of the mobile device. For example, 14.5.1.

Device Trust

mobile_device.device_brand

Maker of the mobile device. For example Apple, Samsung, or Google.

Device Trust

mobile_device.ip_address

X-Forwarded-For or the source IP address of a client connecting to a web server through an HTTP proxy or a load balancer.

Device Trust

mobile_device.locations

List of geolocation coordinates information captured by the mobile device. (Requires user consent and permission.)

For details, see Sample Mobile Request.

Device Trust

mobile_device.locations.latitude

The latitude property is a double-precision floating point value which represents the latitude of a geographical position, specified in decimal degrees.

Location Risk Analyzer

mobile_device.locations.longitude

The longitude property is a double-precision floating point value which represents the longitude of a geographical position, specified in decimal degrees.

Location Risk Analyzer

mobile_device.locations.log_date

The timestamp at which coordinates data was collected from the user's mobile device.

The timestamp should be in ISO-8601 format.

Location Risk Analyzer

Note

If the context contains the mobile_device key, the type of application in Arculix should be set as mobile_application; otherwise, Arculix will discard the mobile_device key data.

Sample web request

{
  "session_uid":"xxxxx1f1f5a634355702ced92951xxxx",
  "email":"jian-yang@piedpiper.com",
  "event": "post-auth",
  "context": {
    "ip_address":"74.50.231.26",
    "latitude": 50.09951255599202,
    "longitude": -120.98416469567863,
    "accuracy": 50,
    "bfpToken": "xxxxbGciOiJIUzI1NiJ9.xxxxxW5nZXJwcmludCI6IjA3NmIzNWIwNjQ3NzkyNzAyYTk2NmMzMWUwMTY5ZjNiIiwiaGFzaDEiOiJkOWUwNWFhZDM3MmQwODM4YzIyZWNiYjI3MjZmYzY0YSIsImhhc2gyIjoiYmNiNmYyMzVkZTM2YmU5NWY5Yjk4YTE5ZGI5NmQwZjIiLCJoYXNoMyI6IjhkYjljYWY2YWM1MzYzYzAwZmFmZGEzZjdlYzFkN2FiIiwiaGFzaDQiOiJhMzU4ZDUyNjkyNjAyNDRjYTA0MDdmZDIxYzRhNjYwOCIsInJpc2siOjAuNSwiYnJvd3Nlcl9vdXRkYXRlZCI6ZmFsc2V9.l5U-KSI5A1fEz2R9HD6CiViCF9VFfaWLG3BlweYZkoo",
    "auth_method": "totp",
    "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0.3 Safari/605.1.15"
  }
}

Sample mobile application request

{
  "email":"jian-yang@piedpiper.com",
  "session_uid": "session-5faaa6cf22b9d6351c5794de399e33a1",
  "event": "post-auth",
  "context": {
    "mobile_device":
    {
      "device_uid": "D0C3EABF-40D0-4EDE-8DC6-0AB758C82AF0",
      "device_type": "iPhone 11",
      "app_version": "6.2.0",
      "os_type": "iOS",
      "os_version": "13.3",
      "device_brand": "Apple",
      "ip_address": "70.69.146.204",
      "remote_ip_address": "192.168.1.210",
      "locations": [
          {
          "log_date": "2021-05-12T21:56:00+00:00",
          "latitude": 50.09951255599202,
          "longitude": -120.98416469567863
          },
          {
          "log_date": "2021-05-12T10:29:00-07:00",
          "latitude": 51.09951255599202,
          "longitude": -123.98416469567863
          }
      ]
    }
  }
}

Response

Successful response

Field

Type

Description

response_code

String

success

success

Boolean

true

content.loa_score

Float

LOA score calculated by the risk engine based on the parameters provided in the request context.

content.message

String

Blank for successful requests.

content.id

Integer

Internal risk session ID.

content.risk_analyzers

Array

Risk analyzer result objects describing the reason behind the LOA score

Successful response example

{
  "response_code": "success",
  "content": {
    "id": 100,
    "message": "",
    "success": true,
    "loa_score": 2.9,
    "risk_analyzers": [
      {
        "id": 1,
        "data": {
          "hash1": "6a5057d0727ba9e96c9c64ad174518f5",
          "hash2": "75d9149d8bb2316b34dc1bf642c7ce84",
          "hash3": "95a4eba02f8986ba7e74cca5450219c1",
          "hash4": "48bcd22cd441408ba438a64929185b75",
          "fingerprint": "f834686715c5aefd0109e337e2f9fe14"
        },
        "name": "DBFP",
        "reasons": {
          "hash2": 1,
          "hash4": 0.25,
          "matched_via": "hash4,hash2",
          "matched_dbfp_id": 3082
        },
        "loa_delta": 1.25,
        "class_name": "RiskDbfpAnalyzer",
        "updated_at": "2021-02-12T17:52:12.607-08:00",
        "description": "Provides LOA Score Analysis based on Browser fingerprints"
      },
      {
        "id": 4,
        "data": {
          "mobile_vs_auth_request_distance_in_meters": 6.16
        },
        "name": "GPS",
        "reasons": {
          "mobile_browser_proximity": "6.16 meters"
        },
        "loa_delta": 4,
        "class_name": "RiskLocationAnalyzer",
        "updated_at": "2021-02-12T17:52:12.616-08:00",
        "description": "Provides LOA Score Analysis based on the GPS coordinates of requests"
      },
      {
        "id": 2,
        "data": {
          "ip_address": "76.115.75.122"
        },
        "name": "IP",
        "reasons": {
          "known_exclusive_user_ip_address": 4
        },
        "loa_delta": 4,
        "class_name": "RiskIpAnalyzer",
        "updated_at": "2021-02-12T17:52:12.631-08:00",
        "description": "Provides LOA Score Analysis based on the IP address of requests"
      }
    }
  }
}

Unsuccessful response

Field

Type

Description

response_code

String

Always invalid for unsuccessful requests.

message

String

Informative message describing the error.

content.loa_score

Integer

0 for unsuccessful requests.

Unsuccessful response examples

HTTP/1.1 401

{
  "response_code": "invalid",
  "message": "Risk Engine APIs are not enabled for this application. please contact SecureAuth Support for more information.",
  "content": {
    "loa_score": 0.0
  }
}
HTTP/1.1 422

{
  "response_code": "invalid",
  "message": "Email domain is not owned by your organization.",
  "content": {
    "loa_score": 0.0
  }
}
HTTP/1.1 422

{
  "response_code": "invalid",
  "message": "Unable to create the user with 1234-xyz: Invalid email address format.",
  "content": {
    "loa_score": 0.0
  }
}

Notification

After initiating an authentication request, the relying party has the option of getting notified as soon as the MFA phase is complete. This can be a result of the user taking action to approve or reject the request or the request having expired.

To listen for the notification, the relying party should use the channel returned by the initial user authentication request to subscribe to the Arculix Faye server. Use the following JavaScript snippet (written using jQuery but vanilla JavaScript works as well).

<script src="https://faye.acceptto.com/faye/faye.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<script type="text/JavaScript">
  $(function() {
      var faye = new Faye.Client("https://faye.acceptto.com/faye");
      faye.subscribe("/messages/<%= @channel %>", function (data) {
          window.location.reload(); // refresh the page and call check api on refresh
      });
  });
</script>

As soon as the MFA phase is complete, a notification is sent to Faye which relays it to any relying party subscribed to the channel and the code block inside faye.subscribe executes. Make sure that you are replacing the <%= @channel %> with the channel returned by the user authentication call and customize the code block inside faye.subscribe; the method above simply refreshes the page but generally a redirection to a results page is used.

MFA integration with device browser fingerprint

Use the following steps to integrate MFA with DBFP.

  1. In the body element of your HTML page, add the following DBFP JavaScript file script:

    <!-- Arculix DBFP -->
      <script type="text/JavaScript" src="https://dbfp.acceptto.com/bfp6.js"></script>
    <!-- End Arculix DBFP --> 
    

    This script sets a cookie named jwt that can be passed as a parameter to the initial user authentication APIs using the key bfpToken or jwt. Arculix uses this data to assess the risk of the authentication request including browser fingerprint, IP address of user and GPS location of the user’s browser. The server compares this data with the history of user behavior data to detect anomalies.

  2. Save your changes.