Authsignal actions are the building blocks that let you create contextual, risk-based authentication flows.

Actions represent specific user activities or events in your application that might require authentication. These can range from routine operations like sign-in to high-risk activities like withdrawing funds, changing account settings, or making large purchases.

Creating an action

To create an action, navigate to the actions page and click the Create a new action button.

Core components of an action

1. Action outcomes

Every action in Authsignal results in one of four possible outcomes that determine how to handle the user’s request:

  • ALLOW: Let the action proceed without additional authentication
  • CHALLENGE: Require the user to complete an authentication challenge
  • REVIEW: Place the action in a queue for manual review
  • BLOCK: Prevent the action from proceeding entirely

Each action has a configurable default outcome that determines what happens when no rules are triggered. However, when you create rules for an action, those rules can override the default outcome.

2. Rules

The conditional logic that determines which outcome to apply based on risk factors and context. Rules can override the action’s default outcome. When you track an action, you provide the context needed for evaluation:

await authsignal.track({
  userId: "0272c312-e181-4cad-a494-43647b503a0a", // Unique identifier for the user
  action: "withdraw-funds", // The action code (what the user is doing)
  attributes: {
    // Contextual information for rule evaluation
    deviceId: "device-abc",
    ipAddress: "203.0.113.1",
    userAgent: "Mozilla/5.0...",
  },
});

Setting up your action

1. Tracking an action

In your app’s backend, use an Authsignal Server SDK to track an action which represents what your user is doing (e.g. withdraw-funds).

This step will return a token which can be passed to a client SDK to perform a challenge for that user.

// Track an action on your backend
const result = await authsignal.track({
  userId: "0272c312-e181-4cad-a494-43647b503a0a",
  action: "withdraw-funds",
  attributes: {
    deviceId: "deviceId",
    ipAddress: "ipAddress",
  },
});

// Handle different action outcomes
if (result.state === "CHALLENGE_REQUIRED") {
  // User needs to complete a challenge
  return {
    token: result.token, 
  };
} else if (result.state === "ALLOW") {
  // Proceed with the action
  return { success: true };
} else if (result.state === "REVIEW") {
  // Action requires manual review
  return { 
    status: "under_review",
    message: "Your request is being reviewed"
  };
} else if (result.state === "BLOCK") {
  // Action is blocked
  return { 
    error: "This action cannot be completed for security reasons"
  };
}

2. Challenging the user

Challenging the user performing an action.

In your frontend, call setToken with the client token obtained, then use the relevant SDK methods to progress the user through a challenge.

// Set the token from the track result
authsignal.setToken(token);

// Show the appropriate challenge based on the user's enrolled methods
const result = await authsignal.passkey.signIn({
  action: "withdraw-funds"
});

// Send the result token back to your server for validation
if (result.token) {
  await validateChallenge(result.token);
}

3. Validating a challenge

After the user completes the challenge, you’ll receive a token that you can validate on your backend to verify the authentication result.

For pre-built UI, this token is appended to your redirect URL as a query parameter, while for custom UI implementation, you’ll get the token directly from the challenge completion result.

Pass the token obtained from the challenge result to your backend and validate it server-side to complete authentication.

const request = {
  token: "eyJhbGciOiJ...", // Token from challenge completion
};

const response = await authsignal.validateChallenge(request);

if (response.state === "CHALLENGE_SUCCEEDED") {
  // The user completed the challenge successfully
  // Proceed with authenticated action or create authenticated session
  return { success: true, userId: response.userId };
} else {
  // The user did not complete the challenge successfully
  return { error: "Challenge validation failed" };
}