> ## 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.

# Programmatically managing authenticators on behalf of users

> Learn how to automatically enroll and un-enroll users' authentication methods.

Programmatic authenticator management allows you to automatically enroll or remove authenticators on behalf of users without requiring their direct interaction. This is useful for:

* **Registration flows** - Auto-enroll users with verified email/SMS during signup
* **Admin operations** - Remove compromised or outdated authenticators
* **Account migrations** - Transfer existing verified contact methods to Authsignal
* **Bulk operations** - Manage authenticators for multiple users programmatically

<Warning>
  **Use with caution:** Programmatic management bypasses normal user verification flows. Only use
  these methods when you've already verified user contact information in your own system.
</Warning>

## Adding authenticators

### When to use programmatic enrollment

Programmatic enrollment is ideal when:

* You've already verified a user's email/phone in your registration flow
* You're migrating users from another authentication system
* You want to streamline onboarding by pre-enrolling verified methods

### Supported methods

You can programmatically enroll the following verification methods:

| Method             | Required Field                        | Description                           |
| ------------------ | ------------------------------------- | ------------------------------------- |
| `EMAIL_OTP`        | `email`                               | Email-based one-time passwords        |
| `EMAIL_MAGIC_LINK` | `email`                               | Email magic links                     |
| `SMS`              | `phoneNumber`                         | SMS-based one-time passwords          |
| `PASSKEY`          | `credentialId`, `credentialPublicKey` | Passkeys (WebAuthn). Optional: `name` |

### Implementation

<CodeGroup>
  ```ts Node.js theme={null}
  const request = {
    userId: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
    attributes: {
      verificationMethod: VerificationMethod.SMS,
      phoneNumber: "+64270000000",
    },
  };

  const response = authsignal.enrollVerifiedAuthenticator(request);
  ```

  ```csharp C# theme={null}
  var request = new EnrollVerifiedAuthenticatorRequest(
      UserId: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
      Attributes: new EnrollVerifiedAuthenticatorAttributes(
          VerificationMethod: VerificationMethod.SMS,
          PhoneNumber: "+64270000000"
      )
  );

  var response = await authsignal.EnrollVerifiedAuthenticator(request);
  ```

  ```java Java theme={null}
  EnrollVerifiedAuthenticatorRequest request = new EnrollVerifiedAuthenticatorRequest();
  request.userId = "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833";
  request.attributes = new EnrollVerifiedAuthenticatorAttributes();
  request.attributes.verificationMethod = VerificationMethodType.SMS;
  request.attributes.phoneNumber = "+64270000000";

  authsignal.enrollVerifiedAuthenticator(request).get();
  ```

  ```ruby Ruby theme={null}
  Authsignal.enroll_verified_authenticator(
      user_id: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
      attributes:{
          verification_method: "SMS",
          phone_number: "+64270000000"
      }
  )
  ```

  ```python Python theme={null}
  response = authsignal.enroll_verified_authenticator(
      user_id="dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
      attributes={
          "verificationMethod": "SMS",
          "phoneNumber": "+64270000000"
      }
  )
  ```

  ```php PHP theme={null}
  $response = Authsignal::enrollVerifiedAuthenticator([
      'userId' => "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
      'attributes' => [
          "verificationMethod" => "SMS",
          "phoneNumber" => "+64270000000"
      ]
  ]);
  ```

  ```go Go theme={null}
  response, err := client.EnrollVerifiedAuthenticator(
      EnrollVerifiedAuthenticatorRequest{
          UserId: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
          Attributes: &EnrollVerifiedAuthenticatorAttributes{
              VerificationMethod: "SMS",
              PhoneNumber: "+64270000000",
          },
      },
  )

  ```
</CodeGroup>

<Warning>
  This method assumes the user's contact information has already been verified in your system. Never
  enroll unverified email addresses or phone numbers.
</Warning>

## Removing authenticators

### When to use programmatic removal

Administrative removal is appropriate for:

* **Security incidents** - Remove compromised authenticators immediately
* **User support** - Help users who've lost access to their methods
* **Account cleanup** - Remove outdated or duplicate authenticators
* **Compliance** - Ensure users only have approved authentication methods

### Implementation

<CodeGroup>
  ```ts Node.js theme={null}
  const request = {
    userId: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
    userAuthenticatorId: "bf287470-24d9-4aa4-8b29-85683bea703f",
  };

  await authsignal.deleteAuthenticator(request);
  ```

  ```csharp C# theme={null}
  var request = new DeleteAuthenticatorRequest(
      UserId: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
      UserAuthenticatorId: "bf287470-24d9-4aa4-8b29-85683bea703f"
  );

  await authsignal.DeleteAuthenticator(request);
  ```

  ```java Java theme={null}
  DeleteAuthenticatorRequest request = new DeleteAuthenticatorRequest();
  request.userId = "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833";
  request.userAuthenticatorId = "bf287470-24d9-4aa4-8b29-85683bea703f";

  authsignal.deleteAuthenticator(request).get();
  ```

  ```ruby Ruby theme={null}
  Authsignal.delete_authenticator(
      user_id: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
      user_authenticator_id: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833"
  )
  ```

  ```python Python theme={null}
  authsignal.delete_authenticator(
      user_id="dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
      user_authenticator_id="bf287470-24d9-4aa4-8b29-85683bea703f"
  )
  ```

  ```php PHP theme={null}
  Authsignal::deleteAuthenticator([
      'userId' => "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
      'userAuthenticatorId' => "bf287470-24d9-4aa4-8b29-85683bea703f"
  ]);
  ```

  ```go Go theme={null}
  err := client.DeleteAuthenticator(
      DeleteAuthenticatorRequest{
          UserId:              "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
          UserAuthenticatorId: "bf287470-24d9-4aa4-8b29-85683bea703f",
      },
  )

  ```
</CodeGroup>

**Getting authenticator IDs:**
To remove an authenticator, you need its `userAuthenticatorId`. Get this via:

```javascript theme={null}
// Get all authenticators for a user
const authenticators = await authsignal.getAuthenticators({
  userId: "user-id",
});

// Find the specific authenticator to remove
const emailAuthenticator = authenticators.find((auth) => auth.verificationMethod === "EMAIL_OTP");

// Remove it
await authsignal.deleteAuthenticator({
  userId: "user-id",
  userAuthenticatorId: emailAuthenticator.userAuthenticatorId,
});
```

<Warning>
  **Account lockout risk:** Removing all of a user's authenticators will prevent them from
  completing authentication challenges. Always ensure users have at least one working authenticator
  or a way to re-enroll.
</Warning>

## Next steps

* [Understanding authenticator binding](/advanced-usage/authenticator-binding)
