PHP Server SDK
Dodgeball Server Trust SDK for PHP
Table of Contents
Purpose
Dodgeball enables developers to decouple security logic from their application code. This has several benefits including:
- The ability to toggle and compare security services like fraud engines, MFA, KYC, and bot prevention.
- Faster responses to new attacks. When threats evolve and new vulnerabilities are identified, your application's security logic can be updated without changing a single line of code.
- The ability to put in placeholders for future security improvements while focussing on product development.
- A way to visualize all application security logic in one place.
The Dodgeball Server Trust SDK for PHP makes integration with the Dodgeball API easy and is maintained by the Dodgeball team.
Prerequisites
You will need to obtain an API key for your application from the Dodgeball developer center.
Related
Check out the Dodgeball Trust Client SDK for how to integrate Dodgeball into your frontend applications.
Installation
Use composer to install the Dodgeball module:
composer require dodgeball/dodgeball-sdk-serverUsage
<?php
use Dodgeball\DodgeballSdkServer\Dodgeball;
$dodgeball = new Dodgeball('secret-api-key...');
$checkpointResponse = $dodgeball->checkpoint([
'checkpointName' => 'PLACE_ORDER',
'event' => (object) [
'ip' => $_SERVER['REMOTE_ADDR'], // Make sure this is the real IP address of the client
'data' => (object) [
'key' => 'value',
'nested' => (object) [
'key' => 'nestedValue',
],
],
],
'sourceToken' => $_SERVER['HTTP_X_DODGEBALL_SOURCE_TOKEN'],
'sessionId' => $currentSessionId,
'userId' => $currentUserId,
'useVerificationId' => $_SERVER['HTTP_X_DODGEBALL_VERIFICATION_ID']
]);API
Configuration
The package requires a secret API key as the first argument to the constructor.
$dodgeball = new Dodgeball("secret-api-key...");Optionally, you can pass in configuration options:
$dodgeball = new Dodgeball("secret-api-key...", [
'apiVersion' => "v1",
'apiUrl' => "https://api.dodgeballhq.com",
'isEnabled' => true
]);| Option | Default | Description |
|---|---|---|
apiVersion | v1 | The Dodgeball API version to use. |
apiUrl | https://api.dodgeballhq.com | The base URL of the Dodgeball API. Useful for sending requests to different environments such as https://api.sandbox.dodgeballhq.com. |
isEnabled | true | Whether to make actual calls to Dodgeball. Set to false for local development to prevent invoking checkpoints and submitting tracked events. |
Call a Checkpoint
Checkpoints represent key moments of risk in an application. A checkpoint can represent any activity deemed to be a risk — login, placing an order, redeeming a coupon, posting a review, changing bank account information, making a donation, transferring funds, creating a listing.
$checkpointResponse = $dodgeball->checkpoint([
'checkpointName' => "CHECKPOINT_NAME",
'event' => (object) [
'ip' => $_SERVER['REMOTE_ADDR'],
'data' => (object) [
'transaction' => (object) [
'amount' => 100,
'currency' => 'USD',
],
'paymentMethod' => (object) [
'token' => 'ghi789'
]
],
],
'sourceToken' => 'abc123...', // Obtained from the Dodgeball Client SDK
'sessionId' => 'session_def456', // The current session ID of the request
'userId' => 'user_12345', // The user ID in your database (after registration); leave blank if unknown
'useVerificationId' => 'def456' // Optional, if you have a verification ID
]);| Parameter | Required | Description |
|---|---|---|
checkpointName | true | The name of the checkpoint to call. |
event | true | The event to send to the checkpoint. |
event.ip | true | The IP address of the device where the request originated. |
event.data | false | Object containing arbitrary data to send to the checkpoint. |
sourceToken | Either sessionId or sourceToken required | A Dodgeball generated token representing the device making the request. |
sessionId | Either sessionId or sourceToken required | The current session ID of the request. |
userId | false | The user ID in your database (after registration). Leave blank if unknown. |
useVerificationId | false | If a previous verification was performed, pass it here. See useVerification. |
Interpreting the Checkpoint Response
Calling a checkpoint creates a verification in Dodgeball. The status and outcome determine how your application should proceed.
$checkpointResponse = [
'success' => boolean,
'errors' => [
[
'code' => int,
'message' => string
]
],
'version' => string,
'verification' => [
'id' => string,
'status' => string,
'outcome' => string
]
];| Property | Description |
|---|---|
success | Whether the request was successful or failed. |
errors | If success is false, contains an array of error objects with code and message. |
version | The Dodgeball API version used. Default is v1. |
verification | Object representing the verification performed at this checkpoint. |
verification.id | The ID of the verification created. |
verification.status | The current status. See Verification Statuses. |
verification.outcome | The outcome. See Verification Outcomes. |
Verification Statuses
| Status | Description |
|---|---|
COMPLETE | The verification was completed successfully. |
PENDING | The verification is currently processing. |
BLOCKED | The verification is waiting for input from the user. |
FAILED | The verification encountered an error and was unable to proceed. |
Verification Outcomes
| Outcome | Description |
|---|---|
APPROVED | The request should be allowed to proceed. |
DENIED | The request should be denied. |
PENDING | A determination has not been reached yet. |
ERROR | The verification encountered an error and was unable to make a determination. |
Possible Checkpoint Responses
Approved — status: 'COMPLETE', outcome: 'APPROVED'
Denied — status: 'COMPLETE', outcome: 'DENIED'
Pending — status: 'PENDING', outcome: 'PENDING' (still processing)
Blocked — status: 'BLOCKED', outcome: 'PENDING' (awaiting user input, e.g. MFA)
Undecided — status: 'COMPLETE', outcome: 'PENDING' (finished but no determination reached)
Error — success: false, status: 'FAILED', outcome: 'ERROR'
Utility Methods
It is strongly advised to use these methods rather than directly interpreting the checkpoint response.
$checkpointResponse->isAllowed()
$checkpointResponse->isAllowed()Returns true if the request is allowed to proceed.
$checkpointResponse->isDenied()
$checkpointResponse->isDenied()Returns true if the request is denied and should not proceed.
$checkpointResponse->isRunning()
$checkpointResponse->isRunning()Returns true if no determination has been reached. Return the verification to the frontend to gather additional user input. See useVerification.
$checkpointResponse->isUndecided()
$checkpointResponse->isUndecided()Returns true if the verification has finished with no determination reached.
$checkpointResponse->hasError()
$checkpointResponse->hasError()Returns true if the response contains an error.
$checkpointResponse->isTimeout()
$checkpointResponse->isTimeout()Returns true if the verification has timed out. The application decides how to proceed.
useVerification
Sometimes additional input is required from the user before making a determination. For example, if 2FA is required, the checkpoint response will have status: 'BLOCKED' and outcome: 'PENDING'. Return the verification to your frontend and pass it to dodgeball.handleVerification() to prompt the user. Once the user completes the step, pass the resulting verification ID back to your API via useVerification.
Important: To prevent replay attacks, each verification ID can only be passed to useVerification once.
End-to-End Example
// In your frontend application...
const placeOrder = async (order, previousVerificationId = null) => {
const sourceToken = await dodgeball.getSourceToken();
const endpointResponse = await axios.post("/api/orders", { order }, {
headers: {
"x-dodgeball-source-token": sourceToken,
"x-dodgeball-verification-id": previousVerificationId
}
});
dodgeball.handleVerification(endpointResponse.data.verification, {
onVerified: async (verification) => {
await placeOrder(order, verification.id);
},
onApproved: async () => {
setIsOrderPlaced(true);
},
onDenied: async (verification) => {
setIsOrderDenied(true);
},
onError: async (error) => {
setError(error);
setIsPlacingOrder(false);
}
});
}use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
// In your API...
Route::post('/api/orders', function(Request $request) {
$order = $request->input('order');
$checkpointResponse = $dodgeball->checkpoint([
'checkpointName' => 'PLACE_ORDER',
'event' => [
'ip' => $request->ip(),
'data' => [
'order' => $order,
],
],
'sourceToken' => $request->header('x-dodgeball-source-token'),
'sessionId' => $request->session()->getId(),
'userId' => $request->session()->get('userId'),
'useVerificationId' => $request->header('x-dodgeball-verification-id'),
]);
if ($checkpointResponse->isAllowed()) {
$placedOrder = app('database')->createOrder($order);
return response()->json(['order' => $placedOrder]);
} else if ($checkpointResponse->isRunning()) {
return response()->json(['verification' => $checkpointResponse->verification], 202);
} else if ($checkpointResponse->isDenied()) {
return response()->json(['verification' => $checkpointResponse->verification], 403);
} else {
return response()->json(['message' => $checkpointResponse->errors], 500);
}
});Track an Event
You can track additional information about a user's journey by submitting tracking events from your server. This data is added to the user's profile and made available to checkpoints.
$dodgeball->event([
'event' => [
'type' => 'EVENT_NAME', // Can be any string you choose
'data' => [
'transaction' => [
'amount' => 100,
'currency' => 'USD',
],
'paymentMethod' => [
'token' => 'ghi789',
],
],
],
'sourceToken' => 'abc123...',
'sessionId' => 'session_def456',
'userId' => 'user_12345',
]);| Parameter | Required | Description |
|---|---|---|
event | true | The event to track. |
event.type | true | A name representing where in the journey the user is. |
event.data | false | Object containing arbitrary data to track. |
sourceToken | Either sessionId or sourceToken required | A Dodgeball generated token representing the device. |
sessionId | Either sessionId or sourceToken required | The current session ID. |
userId | false | The user ID in your database (after registration). Leave blank if unknown. |
Running Tests
This package uses PHPUnit for testing. To run the tests from the root of the project:
./vendor/bin/phpunit --display-warnings --display-deprecations testsUpdated about 2 hours ago
