Pular para o conteúdo principal
Versão: Guardian v0.3.1

Verify Transactions

Call verify() at security-sensitive moments. The SDK collects device signals, performs attestation, and returns the backend's risk decision.

verify() requires a fresh JWT that your backend mints. The SDK never holds a Surt API key - your backend holds the sp_live_* key (server-side only) and exchanges it for a short-lived JWT.

Basic Usage

First, fetch a fresh JWT from your own backend, then pass it to verify():

PaymentScreen.tsx
import { useGuardian } from '@surtai/guardian-rn';

// Your backend calls Surt's POST /geolocation/preflight with the
// sp_live_* API key and returns the minted JWT to the client.
async function fetchVerifyJwt(): Promise<string> {
const res = await fetch('https://your-api.com/guardian/jwt', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
transaction_type: 'withdrawal',
transaction_name: 'User Payment',
}),
});
const { token } = await res.json();
return token;
}

function PaymentScreen() {
const { verify } = useGuardian();

const handlePayment = async () => {
try {
const jwt = await fetchVerifyJwt();
const result = await verify(jwt);

if (result.allowed) {
// Proceed with payment
} else {
// Transaction denied - check result.riskLevel
}
} catch (error) {
// Handle SDK error (network, not initialized, invalid jwt, etc.)
}
};

return <Button onPress={handlePayment} title="Pay" />;
}
aviso

Always fetch a fresh JWT immediately before each verify() call. The attestation nonce bound to the JWT is single-use - reusing a JWT causes an attestation failure.

Where Customer & Transaction Context Come From

In v0.3.0 the client no longer calls setCustomer() and no longer passes a transaction type to verify(). Instead, your backend sets all of this context when it mints the JWT.

When your backend calls POST /geolocation/preflight, it includes customer_id, transaction_type, and optionally transaction_name, name, and email. Those values are baked into the JWT, so the client only needs to pass the token:

const jwt = await fetchVerifyJwt(); // backend set customer + transaction context
const result = await verify(jwt);

Transaction Types

These values are sent by your backend in the preflight transaction_type field. They are not passed to verify() in the client.

TypeUse case
loginUser login
sign_upNew account creation
depositAdding funds
withdrawalWithdrawing funds

Per-Call Location Override

Override the collectLocation default for a single call:

// Skip location for this call
const result = await verify(jwt, { collectLocation: false });

// Request location for this call
const result = await verify(jwt, { collectLocation: true });

// Use init default
const result = await verify(jwt);

The override is one-shot. It only affects that single verify() call.

How Location Collection Is Decided

Location collection has two levels of control, evaluated together. Both must agree for GPS data to be collected:

1. Surt Dashboard: GPS enabled (highest priority)

GPS collection must be enabled in your Surt client panel. If GPS is disabled in the dashboard, location is never collected regardless of what you set in code. Enable it in Settings > Developer or contact your Surt account manager.

2. Client-side setting (your code)

This is resolved as: per-call override > init default.

  • If you pass { collectLocation: true } to verify(), that wins over the init value.
  • If you pass { collectLocation: false } to verify(), GPS is skipped even if init was true.
  • If you omit it, the init default from GuardianProvider / initialize() is used.

In practice, this means:

Dashboard GPSYour code saysResult
enabledtrue (init or override)GPS collected
enabledfalse (init or override)No GPS: you opted out
disabledtrue (init or override)No GPS: dashboard has it off
disabledfalse (init or override)No GPS
Key takeaway

Your client-side collectLocation setting can only opt out of location collection. It cannot force GPS collection if the dashboard has it disabled. To enable GPS collection, turn it on in your Surt client panel first, then set collectLocation: true in your code.

Verification Result

interface VerificationResult {
allowed: boolean; // Backend decision - true = proceed
riskLevel: RiskLevel; // 'low' | 'medium' | 'high' | 'blocked' | 'unknown'
sessionId: string; // Transaction ID for support reference
errors?: string[]; // Backend error messages, if any
timestamp: number; // Response timestamp (ms)
metadata?: Record<string, any>; // Additional backend metadata
}

For risk level details, see Risk Levels.

Full Example

App.tsx
import React, { useState } from 'react';
import { View, Button, Text, Alert } from 'react-native';
import {
GuardianProvider,
useGuardian,
type VerificationResult,
} from '@surtai/guardian-rn';

// Your backend calls Surt's POST /geolocation/preflight with the
// sp_live_* API key and returns the minted JWT to the client.
async function fetchVerifyJwt(): Promise<string> {
const res = await fetch('https://your-api.com/guardian/jwt', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
transaction_type: 'login',
transaction_name: 'User Login',
}),
});
const { token } = await res.json();
return token;
}

function HomeScreen() {
const { verify, collect, isInitialized } = useGuardian();
const [result, setResult] = useState<VerificationResult | null>(null);

const handleLogin = async () => {
try {
const jwt = await fetchVerifyJwt();
const res = await verify(jwt);
setResult(res);
Alert.alert(res.allowed ? 'Approved' : 'Denied', `Risk: ${res.riskLevel}`);
} catch (e: any) {
Alert.alert('Error', e.message);
}
};

return (
<View style={{ padding: 20 }}>
<Text>SDK Ready: {isInitialized ? 'Yes' : 'No'}</Text>
<Button title="Login & Verify" onPress={handleLogin} />
{result && <Text>Allowed: {result.allowed ? 'Yes' : 'No'}</Text>}
</View>
);
}

export default function App() {
return (
<GuardianProvider environment="production" collectLocation={true}>
<HomeScreen />
</GuardianProvider>
);
}