Automated Recovery Flow

This chapter assumes that you have completed the Full Integration.


Automating the account recovery flow is an effective way of letting your users resolve their own risky activity without involving analysts or support people.

This guide is for building a custom integration subscribing to Castle's webhooks and hosting your own email delivery and password reset flow.

Step 1. Log out Malicious Sessions

Instead of tracking $login.succeeded via the track call, the event should instead be "Authenticated" as described in the adaptive authentication section.

When action is deny, simply log out the current session and wait for the $incident.confirmed webhook. You must not reset a user account based on the deny response, but instead let the user initiate a password reset after they have received the security notification.

begin
  verdict = castle.authenticate(
    event: '$login.succeeded',
    user_id: 'e325bcdd10ac',
    user_traits: {
      email: 'johan@castle.io',
      created_at: '2015-02-23T22:28:55.387Z'
    }
  )
rescue Castle::Error => e
  puts e.message
end

if verdict[:action] == 'deny'
  # IMPLEMENT: Log out the user
end
<?
$verdict = Castle::authenticate(array(
  'event' => '$login.succeeded',
  'user_id' => 'e325bcdd10ac',
  'user_traits' => array(
    'email' => 'johan@castle.io',
    'created_at' => '2015-02-23T22:28:55.387Z'
  )
));

if ($verdict->action == 'deny') {
  // IMPLEMENT: Log out the user
}
verdict = castle.authenticate({
    'event': '$login.succeeded',
    'user_id': 'e325bcdd10ac',
    'user_traits': {
        'email': 'johan@castle.io',
        'created_at': '2015-02-23T22:28:55.387Z'
    }
})

if verdict['action'] == 'deny':
    # IMPLEMENT: Log out the user
curl https://api.castle.io/v1/authenticate \
  -u ":YOUR-API-SECRET" \
  -H "Content-Type: application/json" \
  -d '
  {
    "event": "$login.succeeded",
    "user_id": "e325bcdd10ac",
    "context": {
      "client_id": "a97b492d-dcc3-4fc1-87d6-65682955afa5",
      "ip": "37.46.187.90",
      "headers": {
        "User-Agent": "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko",
        "Accept": "text/html",
        "Accept-Language": "en-us,en;q=0.5"
      }
    },
    "user_traits": {
      "email": "johan@castle.io",
      "created_at": "2015-02-23T22:28:55.387Z"
    }
  }'

Step 2. Subscribe to the Incident webhook

Head over to the webhook settings in the Castle Dashboard and subscribe to the $incident.confirmed event. This event will be triggered whenever the risk of a device exceeds 90, and will only trigger once per device.

See webhooks section of the documention for details on how to implement the Castle webhooks on your backend.

Step 3. Implement the security email

You should now create an security notification email based on the context from the webhook, and set the email subject to something like "Prevented login from Safari on Mac OS X".

  1. Populate the device and location data from the webhook payload
  2. Link to the password reset flow for your site, eg. https://yourcompany.com/password/new

Example

Review email

Step 4. Track the password reset event

If you haven't implemented this already, when the user successfully completes the password reset flow, a $password_reset.succeeded event should be tracked from the backend. This will remove the reported device from the user profile and exclude it from the user risk score. Reported devices will still be visible in the dashboard, but marked as "Mitigated".

Example

castle.track(
  event: '$password_reset.succeeded',
  user_id: user.id
)
castle.track(
    {
        'event': '$password_reset.succeeded',
        'user_id': user.id
    }
)
<?
Castle::track(
  array(
    'event' => '$password_reset.succeeded',
    'user_id' => $user->id
  )
);
castle.track(
  "$password_reset.succeeded",
  user_id
);
curl https://api.castle.io/v1/track \
  -X POST \
  -u ":YOUR-API-SECRET" \
  -H "Content-Type: application/json" \
  -d '
    {
      "event": "$password.reset_succeeded",
      "user_id": "1234"
      "context": {
        "client_id": "a97b492d-dcc3-4fc1-87d6-65682955afa5",
        "ip": "37.46.187.90",
        "headers": {
          "User-Agent": "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko",
          "Accept": "text/html",
          "Accept-Language": "en-us,en;q=0.5"
        }
      }
    }'

Mitigated device

Mitigated Devices