User Devices List

Important: This guide is intended for a Device List that will be displayed to your end users, and allows your end users to manage their own devices. If you want to build a Device Management Tool that will be used by internal administrators and support teams, please follow the guide for building a Device Management Tool for Admins.

Note: This chapter assumes that you have completed the Baseline, Account Recovery, and Engaging Your Users integrations.

Intro to User Devices List

In order to build trust with your users over time -- and to minimize manual support overhead -- it is best to proactively give your users a way to review abnormal activity on their accounts so that they can report and resolve incidents on their own. This section of the guide is for building a landing page that shows a user a list of the devices that are accessing their account. This will allow users to review each of the devices, and manual approve or report any of the devices. This allow users to proactively participate in the security process of their own accounts.

User Devices Landing Page

With the follow steps, you'll be able to build out a landing page where a user can review all of the devices accessing their account and elicit user feedback so that they can approve or report any device. By the end of this step, here is an example of a User Devices Landing Page you'll be able to create for your users and show off in your website or application: User Devices landing page

User Devices API

In order to fetch a list of devices accessing a user's account, call Castle's users/{user-id}/devices endpoint:

Example Request

curl https://api.castle.io/v1/users/{user-id}/devices \
  -X GET \
  -u ":YOUR-API-SECRET" \
  -H "Content-Type: application/json" \

Sample Response - User Devices Endpoint

{
  "total_count": 2,
  "data": [
    {
      "token": "eyJhbGciOiJIUzI1NiJ9.eyJ0b2tlbiI6IkZSWHZnc3pvRWNHejNXYzVic1pjUHBjV3NzRXF1NDhqIiwidmVyc2lvbiI6MC4xfQ.AI5m5rUf97KZQg4o0zITwhNtbdgiAN9C2p3soDTg4sQ",
      "risk": 0.000154,
      "created_at": "2018-06-15T16:36:22.916Z",
      "last_seen_at": "2018-07-19T23:09:29.681Z",
      "approved_at": null,
      "escalated_at": null,
      "mitigated_at": null,
      "context": {
        "ip": "74.102.236.7",
        "location": {
          "country_code": "US",
          "country": "United States",
          "region": "New Jersey",
          "region_code": "NJ",
          "city": "Lyndhurst",
          "lat": 40.7923,
          "lon": -74.1001 
        },
        "user_agent": {
          "raw": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36 OPR/54.0.2952.51",
          "browser": "Opera",
          "version": "54.0.2952",
          "os": "Mac OS X 10.13.6",
          "mobile": false,
          "platform": "Mac OS X",
          "device": "Unknown",
          "family": "Opera"
        },
        "type": "desktop"
      }
    },
    {
      "token": "eyJhbGciOiJIUzJ1NiJ9.eyJ0b2tlbiI6InhDb0hmd3h6VlZlbWR0NEN0Wlk4eGhrc0pHeldnMjdFIiwidmVyc2lvbiI6MC4xfQ.8Ll1-hR-hDjIAO27DgllWllQP6u2XG_syZayU_6FG80",
      "risk": 0.560931,
      "created_at": "2018-06-05T20:54:12.416Z",
      "last_seen_at": "2018-06-05T20:54:12.416Z",
      "approved_at": null,
      "escalated_at": null,
      "mitigated_at": null,
      "context": {
        "ip": "193.106.230.209",
        "location": {
          "country_code": "US",
          "country": "United States",
          "region": "California",
          "region_code": "CA",
          "city": "Goleta",
          "lat": 34.5021,
          "lon": -120.1287
        },
        "user_agent": {
          "raw": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:60.0) Gecko/20100101 Firefox/60.0",
          "browser": "Firefox",
          "version": "60.0",
          "os": "Mac OS X 10.13",
          "mobile": false,
          "platform": "Mac OS X",
          "device": "Unknown",
          "family": "Firefox"
        },
        "type": "desktop"
      }
    }
  ]
}

With this, for each device you can highlight details on the screen to the user.

Additional pieces of UI you'll be able to include are Approve and Report buttons, allowing the user to approve or revoke any given device respectively.

Approving a Device

If the user clicks Approve, track a $challenge.succeeded event to Castle from the backend.

  1. Prompt the user with a confirmation dialogue to ensure they want to confirm the login
  2. Once the user has confirmed the login, track a $challenge.succeeded event from your backend, including the device_token​
  3. Display a prompt informing the user that this device has been approved and no further action is needed
castle.track(
  event: '$challenge.succeeded',
  device_token: device_token
)
castle.track(
    {
        'event': '$challenge.succeeded',
        'device_token': device_token
    }
)
<?
Castle::track(
  array(
    'event' => '$challenge.succeeded',
    'device_token' => $device_token
  )
);
castle.track(
  "$challenge.succeeded",
  device_token
);
curl https://api.castle.io/v1/track \
  -X POST \
  -u ":YOUR-API-SECRET" \
  -H "Content-Type: application/json" \
  -d '
    {
      "event": "$challenge.succeeded",
      "device_token": "{device_token}",
      "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"
        }
      }
    }'

Reporting a Device

If the user clicks Report, track a $review.escalated event to Castle from the backend.

  1. Prompt the user with a confirmation dialogue to ensure they want to report this device
  2. Once the user has confirmed the login, track a $review.escalated event from your backend, including the device_token​
  3. Display a prompt informing the user that this device has been reported, their account has been locked, and they should check for a Reset Password email.

Note: Tracking a $review.escalated event will trigger an $incident.confirmed webhook. Therefore, assuming you have already implemented Objective 2: Account Recovery, the Password Reset email will be automatically sent to this user.

castle.track(
  event: '$review.escalated',
  device_token: device_token
)
castle.track(
    {
        'event': '$review.escalated',
        'device_token': device_token
    }
)
<?
Castle::track(
  array(
    'event' => '$review.escalated',
    'device_token' => $device_token
  )
);
castle.track(
  "$review.escalated",
  device_token
);
curl https://api.castle.io/v1/track \
  -X POST \
  -u ":YOUR-API-SECRET" \
  -H "Content-Type: application/json" \
  -d '
    {
      "event": "$review.escalated",
      "device_token": "{device_token}",
      "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"
        }
      }
    }'