> ## Documentation Index
> Fetch the complete documentation index at: https://docs.authsignal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Flows

> Use Authsignal's server-side SDK methods to start and verify flows.

## Start Flow

<Card title="API schema" icon="file-code" href="/api-reference/server-api/start-flow" horizontal />

This method starts a flow for an action. The action must be a Flows action with a published flow. Identify the user with exactly one of `userId`, `email`, `phoneNumber` or `username`.

Send the user to the returned `challengeUrl` to complete each step in the [pre-built UI](/implementation-options/prebuilt-ui/overview). When they finish, the pre-built UI redirects back to your `redirectUrl` with a `challenge_token`.

<CodeGroup>
  ```ts Node.js theme={null}
  const response = await authsignal.startFlow({
    actionCode: "signIn",
    user: {
      userId: "69904f34-8286-4f35-9484-006a5a22ea1a",
    },
    redirectUrl: "https://yourapp.com/callback",
    clientId: "46194bdd-d865-490c-ac0a-c59c73e628cd",
  });

  const { challengeUrl, challengeToken } = response;
  ```

  ```csharp C# theme={null}
  var request = new StartFlowRequest(
      ActionCode: "signIn",
      User: new UserLookup(UserId: "69904f34-8286-4f35-9484-006a5a22ea1a"),
      RedirectUrl: "https://yourapp.com/callback",
      ClientId: "46194bdd-d865-490c-ac0a-c59c73e628cd"
  );

  var response = await authsignal.StartFlow(request);

  var challengeUrl = response.ChallengeUrl;
  var challengeToken = response.ChallengeToken;
  ```

  ```java Java theme={null}
  StartFlowRequest request = new StartFlowRequest();
  request.actionCode = "signIn";
  request.user = new UserLookup();
  request.user.userId = "69904f34-8286-4f35-9484-006a5a22ea1a";
  request.redirectUrl = "https://yourapp.com/callback";
  request.clientId = "46194bdd-d865-490c-ac0a-c59c73e628cd";

  StartFlowResponse response = authsignal.startFlow(request).get();

  String challengeUrl = response.challengeUrl;
  String challengeToken = response.challengeToken;
  ```

  ```ruby Ruby theme={null}
  response = Authsignal.start_flow(
    action_code: "signIn",
    user: {
      user_id: "69904f34-8286-4f35-9484-006a5a22ea1a"
    },
    redirect_url: "https://yourapp.com/callback",
    client_id: "46194bdd-d865-490c-ac0a-c59c73e628cd"
  )

  challenge_url = response[:challenge_url]
  challenge_token = response[:challenge_token]
  ```

  ```python Python theme={null}
  response = authsignal.start_flow(
      action_code="signIn",
      user={
          "userId": "69904f34-8286-4f35-9484-006a5a22ea1a"
      },
      redirect_url="https://yourapp.com/callback",
      client_id="46194bdd-d865-490c-ac0a-c59c73e628cd"
  )

  challenge_url = response["challenge_url"]
  challenge_token = response["challenge_token"]
  ```

  ```php PHP theme={null}
  $response = Authsignal::startFlow([
      'actionCode' => 'signIn',
      'user' => [
          'userId' => '69904f34-8286-4f35-9484-006a5a22ea1a'
      ],
      'redirectUrl' => 'https://yourapp.com/callback',
      'clientId' => '46194bdd-d865-490c-ac0a-c59c73e628cd'
  ]);

  $challengeUrl = $response['challengeUrl'];
  $challengeToken = $response['challengeToken'];
  ```

  ```go Go theme={null}
  userId := "69904f34-8286-4f35-9484-006a5a22ea1a"
  redirectUrl := "https://yourapp.com/callback"
  clientId := "46194bdd-d865-490c-ac0a-c59c73e628cd"

  response, err := client.StartFlow(
      StartFlowRequest{
          ActionCode:  "signIn",
          User:        &UserLookup{UserId: &userId},
          RedirectUrl: &redirectUrl,
          ClientId:    &clientId,
      },
  )

  challengeUrl := response.ChallengeUrl
  challengeToken := response.ChallengeToken
  ```
</CodeGroup>

## Verify Flow

<Card title="API schema" icon="file-code" href="/api-reference/server-api/verify-flow" horizontal />

This method returns the result of a flow. The action state is `CHALLENGE_SUCCEEDED` once the user has completed every required step, or `CHALLENGE_FAILED` if the flow ended in a Block outcome or the user couldn't complete a step. To get session tokens, enable the JWKS URL for your tenant and pass an app client's ID as `clientId` to Start Flow. Verify Flow then returns access and refresh tokens when the action state is `CHALLENGE_SUCCEEDED` and the user completed at least one verification step. A flow that only enrolls a method doesn't return tokens. See [Session management](/advanced-usage/session-management).

<CodeGroup>
  ```ts Node.js theme={null}
  const response = await authsignal.verifyFlow({
    actionCode: "signIn",
    challengeToken,
  });

  if (response.action.state === "CHALLENGE_SUCCEEDED") {
    const accessToken = response.session?.accessToken;
  }
  ```

  ```csharp C# theme={null}
  var request = new VerifyFlowRequest(
      ActionCode: "signIn",
      ChallengeToken: challengeToken
  );

  var response = await authsignal.VerifyFlow(request);

  if (response.Action.State == FlowState.CHALLENGE_SUCCEEDED)
  {
      var accessToken = response.Session?.AccessToken;
  }
  ```

  ```java Java theme={null}
  VerifyFlowRequest request = new VerifyFlowRequest();
  request.actionCode = "signIn";
  request.challengeToken = challengeToken;

  VerifyFlowResponse response = authsignal.verifyFlow(request).get();

  if (response.action.state == FlowState.CHALLENGE_SUCCEEDED) {
      if (response.session != null) {
          String accessToken = response.session.accessToken;
      }
  }
  ```

  ```ruby Ruby theme={null}
  response = Authsignal.verify_flow(
    action_code: "signIn",
    challenge_token: challenge_token
  )

  if response[:action][:state] == "CHALLENGE_SUCCEEDED"
    access_token = response.dig(:session, :access_token)
  end
  ```

  ```python Python theme={null}
  response = authsignal.verify_flow(
      action_code="signIn",
      challenge_token=challenge_token
  )

  if response["action"]["state"] == "CHALLENGE_SUCCEEDED":
      access_token = response.get("session", {}).get("access_token")
  ```

  ```php PHP theme={null}
  $response = Authsignal::verifyFlow([
      'actionCode' => 'signIn',
      'challengeToken' => $challengeToken
  ]);

  if ($response['action']['state'] === 'CHALLENGE_SUCCEEDED') {
      $accessToken = $response['session']['accessToken'] ?? null;
  }
  ```

  ```go Go theme={null}
  response, err := client.VerifyFlow(
      VerifyFlowRequest{
          ActionCode:     "signIn",
          ChallengeToken: challengeToken,
      },
  )

  if response.Action.State == FlowStateChallengeSucceeded {
      if response.Session != nil {
          accessToken := response.Session.AccessToken
      }
  }
  ```
</CodeGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.