Skip to content

Commit 3f93ceb

Browse files
wallinstayseesongmarkzegarelli
authored
Update Castle destination docs (#3610)
* Update Castle destination docs * Remove getting started section * Apply suggestions from code review Co-authored-by: stayseesong <[email protected]> Co-authored-by: markzegarelli <[email protected]> * Apply more suggestions from code review Co-authored-by: markzegarelli <[email protected]> Co-authored-by: stayseesong <[email protected]> Co-authored-by: markzegarelli <[email protected]>
1 parent 34e5666 commit 3f93ceb

File tree

1 file changed

+41
-153
lines changed
  • src/connections/destinations/catalog/castle

1 file changed

+41
-153
lines changed

src/connections/destinations/catalog/castle/index.md

Lines changed: 41 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -2,200 +2,88 @@
22
title: Castle Destination
33
id: 56a8f566e954a874ca44d3b0
44
---
5-
Once you enable the Castle integration, the [Castle JavaScript snippet](https://docs.castle.io/docs/sdk-browser) is placed on your website, and user data starts appearing in the Castle dashboard.
6-
Client-side tracking works out of the box, however **your existing server-side calls need to be extended** with data from the incoming request.
5+
[Castle](https://castle.io/?utm_source=segmentio&utm_medium=docs&utm_campaign=partners){:target="_blank"} monitors every step of the customer journey to help visualize and proactively block fraud that would otherwise fly under the radar. Types of fraud or abuse that can be managed include bots, fake accounts, multi-accounting, and account sharing.
76

8-
Castle supports calling `identify`, `page`, `screen`, and `group`. Castle does *not* support the `alias` call.
7+
Castle maintains this destination. For any issues with the destination, contact the [Castle support team](mailto:[email protected]).
98

10-
## Integration steps
11-
1. Track successful and failed logins
12-
1. Extend server-side tracking with request properties
13-
1. `identify`, preferably on the server-side
14-
1. _Optional:_ Use Castle's `authenticate` API to request a risk score
15-
1. _Recommended:_ Secure Mode
9+
## Getting Started
1610

17-
## Tracking successful and failed logins
18-
A baseline integration of Castle includes tracking [successful and failed login attempts](https://docs.castle.io/docs/failed-logins). If you track these events using a Segment integration, you can use [Event Mapping](https://dashboard.castle.io/settings/events) to indicate which events correspond to Castle reserved events.
11+
1. Navigate to **Connections > Catalog** in the Segment web app.
12+
2. Search for *Castle* in the **Destinations** tab of the catalog, and select it, and click **Configure Castle**.
13+
3. Choose the sources you want to connect the destination to.
14+
3. Enter the "Publishable Key" the Publishable Key field. Find the Publishable Key on the Castle dashboard.
15+
Calls are now visible in Castle dashboards in real-time.
1916

2017
> info ""
21-
> If you request a Castle risk score for the "Logged in" event, you should **not** map that event to Castle's reserved `$login.succeeded`. Instead, [`authenticate`](https://docs.castle.io/docs/authentication-method) that event through Castle. See next section on _Requesting a risk score_.
18+
> Castle ingests Segment Client-side events. Server-side events are dropped and not processed.
19+
> Castle only supports web integrations through Segment, but is in the process of working on mobile support.
2220
23-
Here are two Ruby examples on how to track successful and failed login attempts (`context` and `integration` have been omitted for brevity):
2421

25-
```ruby
26-
analytics.track(
27-
user_id: '019mr8mf4r',
28-
event: 'Logged in'
29-
)
30-
```
31-
32-
When you track failed logins, you can protect against account threats such as password guessing. If you don't know which user that generated the failed login, omit the `user_id`. Instead, whenever you have access to the user-submitted email field, add this to the event properties as `email` or `username` depending on how you identify your users. Sending both `user_id` and `email` at the same time does not cause any data problems.
33-
34-
```ruby
35-
# known user
36-
analytics.track(
37-
user_id: '019mr8mf4r',
38-
event: 'Failed to log in'
39-
)
40-
# unknown user
41-
analytics.track(
42-
anonymous_id: UUID.generate,
43-
event: 'Failed to log in',
44-
properties: {
45-
46-
}
47-
)
48-
```
49-
50-
> info ""
51-
> Segment requires either `user_id` or `anonymous_id` for the request to be processed. If you don't know which user generated the failed login create a UUID and provide it as `anonymous_id`
52-
53-
## Extending server-side tracking with request properties
54-
Tracking events from your server-side is crucial to prevent requests from getting blocked by malicious actors. This is recommended for all [Castle's reserved events](https://docs.castle.io/docs/events), such as logins and password changes.
5522

56-
> warning ""
57-
> Server-side `track` events are dropped by Castle unless they contain the properties listed below. `identify` calls still create or update a user, but don't create a device if these properties are missing:
58-
> - `context.ip`. The user's IP address, i.e. not your server's internal IP
59-
> - `context.user_agent`, alternatively `context.headers` containing at least the `user_agent` field.
60-
> - `context.client_id`. The _Client ID_ forwarded by the web or mobile SDK.
6123

62-
These properties are described in detail in the next section.
6324

64-
If you aren't tracking the properties above, you can still make the event appear in the user timeline by configuring it to _Force Track_ in the [Castle dashboard](https://dashboard.castle.io/settings/events). However, it does not attach to a device or contribute to the risk score.
25+
## Page
6526

66-
Here's a Ruby example of a server-side `track` call extended with request properties:
27+
If you're not familiar with the Segment Specs, take a look to understand what the [Page call](/docs/connections/spec/page/) does. An example call looks like:
6728

68-
```ruby
69-
analytics.track(
70-
user_id: '019mr8mf4r',
71-
event: 'Logged in'
72-
context: {
73-
ip: '8.8.8.8',
74-
user_agent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.115 Safari/537.36',
75-
client_id: '7a31b5a1-7e01-4377-b086-5a488ec8a0ca',
76-
headers: {
77-
accept_language: 'da, en-gb;q=0.8, en;q=0.7',
78-
...
79-
}
80-
})
29+
```
30+
analytics.page()
8131
```
8232

83-
> **Note:** If you're concerned about sending `client_id` and `headers` to all of your active Segment integrations, instead include them in the `integrations.Castle` object to keep them private to your Castle integration.
84-
85-
### The `client_id` property
86-
By forwarding a client identifier from the client-side to the server-side, you can link activity from the two sources to form a strong protection against attacks where this link is not present.
8733

88-
The Castle JavaScript SDK (loaded by Analytics.js) forwards the client identifier as a browser cookie named `__cid`.
8934

90-
The Castle [iOS](https://docs.castle.io/docs/sdk-ios) and [Android](https://docs.castle.io/docs/sdk-android) SDKs forward it as the HTTP header `X-Castle-Client-Id`. See the respective documentation pages for instructions on how to configure the header forwarding.
35+
Segment sends Page calls to Castle as `$page` events.
9136

92-
Here's a Ruby example on how to extract the Client ID on your server-side:
9337

94-
```ruby
95-
client_id =
96-
request.cookies['__cid'] ||
97-
request.headers['X-Castle-Client-Id']
98-
```
38+
## Track
9939

100-
On **iOS**, forward the device UUID as client identifier:
40+
If you're not familiar with the Segment Specs, take a look to understand what the [Track method](/docs/connections/spec/track/) does. An example call looks like:
10141

102-
```objc
103-
[request setValue:uuid forHTTPHeaderField:@"X-Castle-Client-Id"];
104-
NSURL *url = [NSURL URLWithString:@"https://api.yoursite.com/login"];
105-
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
106-
NSString *uuid = [UIDevice currentDevice].identifierForVendor.UUIDString;
42+
```
43+
analytics.track('Added to Cart')
10744
```
10845

109-
On **Android**, forward the device identifier from Segment's `Utils` package as client identifier:
11046

111-
```java
112-
// com.segment.analytics.internal.Utils
113-
String uuid = Utils.getDeviceId();
114-
OkHttpClient client = new OkHttpClient();
115-
Request request = new Request.Builder()
116-
.url("https://api.yoursite.com/login")
117-
.header("X-Castle-Client-Id", uuid)
118-
.build();
119-
```
12047

121-
> **Note**: If you have a client-less integration, for instance if you're using Castle to protect a customer-facing API, set `client_id` to `false`.
48+
Segment sends Track calls to Castle as a `$custom` events.
12249

123-
### The `headers` property
124-
By forwarding HTTP request headers from the server-side, Castle is able to build a richer device fingerprint and prevent malicious actors from spoofing the client environment.
125-
For privacy reasons, **you do not want to send the "Cookie" header to Castle**, so make sure you delete if from the list of headers.
50+
***
12651

127-
```
128-
{
129-
user_agent: 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)',
130-
accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
131-
accept_language: 'en-us,en;q=0.5',
132-
accept_encoding: 'gzip,deflate',
133-
accept_charset: 'ISO-8859-1,utf-8;q=0.7,*;q=0.7'
134-
}
135-
```
13652

137-
There are example implementations on how to extract request headers in [PHP](https://github.com/castle/castle-php/blob/e93de1532ef28af17b8bf2bef350e6995a580085/lib/Castle/Request.php#L31), [Ruby](https://github.com/castle/castle-ruby), and [Java](https://github.com/castle/castle-java/blob/96cdc7469aa0995a836100c3dfd370b10f299e8c/src/main/java/io/castle/client/objects/UserInfoHeader.java#L148).
13853

139-
## Identify
140-
When you call [`identify`](/docs/connections/spec/identify), a user will be created in Castle. The Segment special traits `email`, `username`, `name`, `createdAt`, `phone`, and `address` are mapped to Castle's reserved user traits.
54+
## Secure Mode
14155

142-
Any additional traits will be stored on the Castle user model as _custom traits_.
56+
Send user information as a signed JWT when you use Castle in production. This prevents bad actors from spoofing any user information.
14357

144-
> **Recommended:** Prevent `identify` from getting blocked in the client during an account takeover by calling `identify` from your server.
58+
In your backend code, encode the user as a JWT and sign it using your Castle "API Secret". When Castle receives the JWT, the integrity of the user data is verified to ensure that the data wasn't tampered with.
14559

146-
Here's a complete JavaScript example of an `identify` call:
60+
Below is an example of how to generate a JWT on your backend using the Ruby language:
14761

148-
```javascript
149-
analytics.identify('1234', {
150-
email: '[email protected]', // recommended
151-
createdAt: '2015-02-23T22:28:55.387Z', // recommended
152-
name: 'Johan Brissmyr', // for display
153-
username: 'brissmyr', // for display
154-
balance: 1350, // custom trait
155-
phone: '+1 415 254 9225', // improved risk scoring
156-
address: { // improved risk scoring
157-
street: '60 Rausch St',
158-
city: 'San Francisco',
159-
state: 'CA',
160-
postalCode: '94103',
161-
country: 'USA'
162-
}
163-
});
62+
```ruby
63+
jwt_from_backend = JWT.encode({
64+
id: '97980cfea0067',
65+
66+
}, ENV.fetch('CASTLE_API_SECRET'), 'HS256')
16467
```
16568

166-
> **Note:** If you call `authenticate` to obtain a risk score, you do *not* need to call `identify` from the server-side. Instead, `authenticate` provides a way to attach `traits` in the same call.
16769

168-
## Secure Mode
169-
Enable Secure Mode to prevent fraudsters from impersonating your users.
170-
171-
> **Note:** Secure Mode is highly encouraged for production deployments, but can wait until after a completed proof a concept.
172-
To enable Secure Mode in Analytics.js, you pass in the `secure` variable by rendering it in your server-side templates. The `secure` field should be a SHA256 hash of your Castle API Secret and the user ID.
17370

174-
Here's an JavaScript example of an `identify` call with Secure Mode being rendered with Ruby server-side templating language:
71+
Transfer the `user_jwt` object to your frontend through a separate API call, or by injecting the code using a templating language:
17572

17673
```javascript
177-
analytics.identify('1234', {
178-
179-
createdAt: '2015-02-23T22:28:55.387Z',
74+
var userJwt = "<%= jwt_from_backend %>";
75+
76+
// Then use the `userJwt` argument instead of `user` when using any of the tracking methods
77+
Castle.page({userJwt: userJwt});
78+
79+
analytics.identify('97980cfea0067', {
80+
18081
}, {
181-
integrations: {
182-
Castle: {
183-
secure: '<%%= OpenSSL::HMAC.hexdigest("sha256", "YOUR_CASTLE_API_SECRET", current_user.id.to_s) %>'
184-
}
82+
Castle: {
83+
userJwt: userJwt
18584
}
18685
});
18786
```
18887

189-
To use secure mode in your mobile app, you will need to first fetch the secure token from your server-side, for example:
190-
191-
```ruby
192-
# GET https://api.yoursite.com/token
193-
def user_token(user_id)
194-
OpenSSL::HMAC.hexdigest("sha256", "YOUR_CASTLE_API_SECRET", user_id.to_s)
195-
end
196-
```
197-
198-
## Requesting a risk score
199-
Castle's adaptive authentication tells you whether to allow access, initiate a second factor of authentication, or log out the user.
20088

201-
Since all Segment calls are called asynchronously, you'll need to use Castle's native SDKs to perform [adaptive authentication](https://docs.castle.io/docs/authentication-method).
89+
When Castle receives a JWT version of the user object, its contents override the user object sent the standard Segment way.

0 commit comments

Comments
 (0)