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

# CrossmintNonCustodialSigner

> Flutter Abstract Base Class

**Abstract Base Class**

Base class for email / phone non-custodial signers.

```dart theme={null}
abstract base class CrossmintNonCustodialSigner implements CrossmintWalletApprovalSigner, CrossmintExportableWalletSigner
```

Signing happens inside a hidden WebView (the Crossmint signer runtime)
coordinated through `CrossmintSignerBridgeClient`. The SDK owns the
WebView's lifecycle via `CrossmintWalletHost` — if it is not mounted,
attempting to use a non-custodial signer throws
`CrossmintSignerException(code: nonCustodialBridgeHostNotMounted)`.

When authentication is needed, the signer calls `onAuthRequired` which
surfaces the OTP challenge to UI (typically via
`CrossmintWalletController.otp`). Concurrent callers are coalesced onto
the same in-flight auth future to avoid double-prompting.

Non-custodial signers are also `CrossmintExportableWalletSigner`s —
email/phone signers can export their private key via
`exportPrivateKey`.

## Constructors

### CrossmintNonCustodialSigner

```dart theme={null}
CrossmintNonCustodialSigner({
  required this.client,
  required this.bridge,
  required this.type,
  required this.locator,
  this.address,
  this.onAuthRequired,
  CrossmintSignerBridgeClient? bridgeClient,
})
```

Creates a non-custodial signer. Prefer the chain-specific factory on `CrossmintClient` (e.g. `createEvmNonCustodialSigner`) over constructing this directly.

## Properties

### client

```dart theme={null}
final CrossmintClient client
```

The client this signer belongs to.

### bridge

```dart theme={null}
final HiddenSignerBridge bridge
```

The hidden signer WebView bridge that hosts the signing runtime.

### type

```dart theme={null}
final String type
```

### locator

```dart theme={null}
final String locator
```

### address

```dart theme={null}
final String? address
```

The wallet address this signer approves for, if known at construction.

### onAuthRequired

```dart theme={null}
final CrossmintSignerAuthRequiredCallback? onAuthRequired
```

Callback invoked when an OTP challenge starts or ends. Usually wired to `CrossmintWalletController.onAuthRequired` — which in turn surfaces a reactive challenge on `CrossmintWalletController.otp`.

### needsAuth

```dart theme={null}
bool get needsAuth
```

`true` while an OTP challenge is outstanding.

### canExportPrivateKey

```dart theme={null}
bool get canExportPrivateKey
```

## Methods

### ensureAuthenticated

```dart theme={null}
Future<void> ensureAuthenticated()
```

Ensures the signer runtime has completed its authentication handshake, prompting the user via `onAuthRequired` if necessary. Concurrent callers share the same in-flight future — the user sees at most one prompt per auth cycle.

### signMessage

```dart theme={null}
Future<String> signMessage(String message)
```

### signTransaction

```dart theme={null}
Future<String> signTransaction(String transaction)
```

### sign

```dart theme={null}
Future<String> sign({
  required CrossmintSignerKeyType keyType,
  required String bytes,
  required CrossmintSignerEncoding encoding,
})
```

Low-level sign primitive — ensures auth, then invokes the signer bridge directly. Chain-specific subclasses wrap this with the encoding / key-type appropriate for their chain.

### sendOtp

```dart theme={null}
Future<void> sendOtp()
```

(Re-)sends the OTP to the signer locator (email / phone). Meant to be invoked via `CrossmintWalletOtpController.sendOtp` during an active challenge.

### exportPrivateKey

```dart theme={null}
Future<void> exportPrivateKey(CrossmintExportSignerBridge bridge)
```

### verifyOtp

```dart theme={null}
Future<void> verifyOtp(String otp)
```

Submits the OTP the user entered. Resolves the pending `ensureAuthenticated` future on success.

### reject

```dart theme={null}
void reject([Object? error])
```

Cancels the pending OTP challenge. Fails the pending `ensureAuthenticated` future with `CrossmintAuthRejectedException` when no cause is supplied.
