Segment makes it easy to send your data to Castle (and lots of other destinations). Once you've tracked your data through our open source libraries we'll translate and route your data to Castle in the format they understand. Learn more about how to use Castle with Segment.
Integrating through Segment
This guide is also available from Segment’s documentation.
Introduction
Once you enable the Castle integration, the Castle JavaScript snippet will be placed on your website, and you will see user data start appearing in the Castle dashboard. Client-side tracking will work out of the box, whereas your existing server-side calls will need to be extended with data from the incoming request.
Castle has support for calling identify
, page
, screen
, and group
. The alias
call is not supported.
Integration steps
- Track successful and failed logins
- Extend server-side tracking with request properties
identify
, preferably on the server-side- Optional: Use Castle’s
authenticate
API to request a risk score - Recommended: Secure Mode
Tracking successful and failed logins
A baseline integration of Castle includes tracking successful and failed login attempts. If you are already tracking these events through your Segment integration, you can use Event Mapping to indicate which of your events that correspond to Castle reserved events.
Note: If you are going to request a Castle risk score for the “Logged in” event, you should not map that event to Castle’s reserved
$login.succeeded
. Instead, you shouldauthenticate
that event through Castle. See next section on Requesting a risk score. Here are two Ruby examples on how to track successful and failed login attempts (context
andintegration
have been omitted for brevity):
analytics.track(
user_id: '019mr8mf4r',
event: 'Logged in'
)
Tracking failed logins enables protection for account threats such as password guessing. If you don’t know which user that generated the failed login, simply omit 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. It’s OK to send both user_id
and email
at the same time.
# known user
analytics.track(
user_id: '019mr8mf4r',
event: 'Failed to log in'
)
# unknown user
analytics.track(
anonymous_id: UUID.generate,
event: 'Failed to log in',
properties: {
email: 'johan@castle.io'
}
)
Note: Segment requires either
user_id
oranonymous_id
for the request to be processed. If you don’t know which user generated the failed login create a UUID and provide it asanonymous_id
Extending server-side tracking with request properties
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, such as logins and password changes.
Important: Server-side
track
events will get dropped by Castle unless they contain the below properties.identify
calls will still create or update a user, but will not create a device if these properties are missing:
context.ip
. The user’s IP address, i.e. not your server’s internal IPcontext.user_agent
, alternativelycontext.headers
containing at least theuser_agent
field.context.client_id
. The Client ID forwarded by the web or mobile SDK.
These properties are described more in detail in the next section.
If you aren’t tracking the above properties, you can still make the event appear in the user timeline by configuring it to Force Track in the Castle dashboard. However, it will not attach to a device or contribute to the risk score. Here’s a Ruby example of a server-side track
call extended with request properties:
analytics.track(
user_id: '019mr8mf4r',
event: 'Logged in'
context: {
ip: '8.8.8.8',
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',
client_id: '7a31b5a1-7e01-4377-b086-5a488ec8a0ca',
headers: {
accept_language: 'da, en-gb;q=0.8, en;q=0.7',
...
}
})
Note: If you’re concerned about sending
client_id
andheaders
to all of your active Segment integrations, instead include them in theintegrations.Castle
object to keep them private to your Castle integration.
The client_id
property
By forwarding a client identifier from the client-side to the server-side, activity from the two sources can be linked together to form a strong protection against attacks where this link is not present.
The Castle JavaScript SDK (loaded by Analytics.js) will forward the client identifier as a browser cookie named __cid
.
The Castle iOS and Android SDKs will forward it as the HTTP header X-Castle-Client-Id
. See the respective documentation pages for instructions on how to configure the header forwarding.
Here’s a Ruby example on how to extract the Client ID on your server-side:
client_id =
request.cookies['__cid'] ||
request.headers['X-Castle-Client-Id']
On iOS, forward the device UUID as client identifier:
[request setValue:uuid forHTTPHeaderField:@"X-Castle-Client-Id"];
NSURL *url = [NSURL URLWithString:@"https://api.yoursite.com/login"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
NSString *uuid = [UIDevice currentDevice].identifierForVendor.UUIDString;
On Android, forward the device identifier from Segment’s Utils
package as client identifier:
// com.segment.analytics.internal.Utils
String uuid = Utils.getDeviceId();
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://api.yoursite.com/login")
.header("X-Castle-Client-Id", uuid)
.build();
Note: If you have a client-less integration, for instance if you’re using Castle to protect a customer-facing API, set
client_id
tofalse
.
The headers
property
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. 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.
{
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)',
accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
accept_language: 'en-us,en;q=0.5',
accept_encoding: 'gzip,deflate',
accept_charset: 'ISO-8859-1,utf-8;q=0.7,*;q=0.7'
}
There are example implementations on how to extract request headers in PHP, Ruby, and Java.
Identify
When you call 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.
Any additional traits will be stored on the Castle user model as custom traits.
Recommended: Prevent
identify
from getting blocked in the client during an account takeover by callingidentify
from your server.
Here’s a complete JavaScript example of an identify
call:
analytics.identify('1234', {
email: 'johan@castle.io', // recommended
createdAt: '2015-02-23T22:28:55.387Z', // recommended
name: 'Johan Brissmyr', // for display
username: 'brissmyr', // for display
balance: 1350, // custom trait
phone: '+1 415 254 9225', // improved risk scoring
address: { // improved risk scoring
street: '60 Rausch St',
city: 'San Francisco',
state: 'CA',
postalCode: '94103',
country: 'USA'
}
});
Note: If you’re calling
authenticate
to obtain a risk score, you do not need to callidentify
from the server-side. Instead,authenticate
provides a way to attachtraits
in the same call.
Secure Mode
Enable Secure Mode to prevent fraudsters from impersonating your users.
Note: Secure Mode is highly encouraged for production deployments, but can wait until after a completed proof a concept. To enable Secure Mode in Analytics.js, you pass in the
secure
variable by rendering it in your server-side templates. Thesecure
field should be a SHA256 hash of your Castle API Secret and the user ID.
Here’s an JavaScript example of an identify
call with Secure Mode being rendered with Ruby server-side templating language:
analytics.identify('1234', {
email: 'johan@castle.io',
createdAt: '2015-02-23T22:28:55.387Z',
}, {
integrations: {
Castle: {
secure: '<%%= OpenSSL::HMAC.hexdigest("sha256", "YOUR_CASTLE_API_SECRET", current_user.id.to_s) %>'
}
}
});
To use secure mode in your mobile app, you will need to first fetch the secure token from your server-side, for example:
# GET https://api.yoursite.com/token
def user_token(user_id)
OpenSSL::HMAC.hexdigest("sha256", "YOUR_CASTLE_API_SECRET", user_id.to_s)
end
Requesting a risk score
Castle’s adaptive authentication tells you whether to allow access, initiate a second factor of authentication, or log out the user.
Since all Segment calls are called asynchronously, you will need to use Castle’s native SDKs to perform adaptive authentication.
Supported Sources and Connection Modes
Web | Mobile | Server | |
---|---|---|---|
📱 Device-based | |||
☁️ Cloud-based | ✅ | ✅ | ✅ |
To learn more about about Connection Modes and what dictates which we support, see here.
Settings
Segment lets you change these destination settings via your Segment dashboard without having to touch any code.
Automatic Page tracking
When you enable automatic page tracking, Castle will track a page view whenever the url of the site changes as opposed to mapping explicitly to your implementation of Segment .page()
calls.
Custom Cookie Domain
If your authenticated area is located at a different domain, use the cookie domain setting to change on which url the cookie is set.
API Publishable Key
You can find your publishable key under Settings in the Castle dashboard. It should look something like this: pk_KmoUyttyEiHCdFTWSqhAF1SL1z9Fi1yg
. This is required and will be used to initialize Castle’s library on your device as well as when you make mobile/server calls through our server side integration.
If you have any questions or see anywhere we can improve our documentation, please let us know or kick off a conversation in the Segment Community!