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

# User Ownership: Non-Custodial Wallets and Asset Control

> SocketFi's non-custodial model: users authorize all transactions, SocketFi cannot access funds, and wallet address is the canonical verified identity.

SocketFi is entirely non-custodial. When you deploy an application on SocketFi, your users own their wallets — not you, and not SocketFi. Every asset a user holds lives in a Soroban smart contract that only they can authorize operations on, because the contract verifies a passkey signature before executing anything. This section explains what that means in practice: what SocketFi can and cannot do, what your application is responsible for, and how to use the wallet address as a reliable user identity in your backend.

## What Non-Custodial Means

In a custodial model, a third party holds private keys and can move funds on users' behalf. SocketFi is the opposite:

|                                              | Custodial Model    | SocketFi (Non-Custodial)    |
| -------------------------------------------- | ------------------ | --------------------------- |
| Who holds the private key?                   | The platform       | The user's device (passkey) |
| Who can authorize transactions?              | The platform       | Only the user               |
| Can the platform freeze funds?               | Yes                | No                          |
| Can the platform move user assets?           | Yes                | No                          |
| What happens if the platform is compromised? | User funds at risk | User funds unaffected       |

SocketFi infrastructure routes requests and verifies authorization, but it never holds signing material that could authorize wallet operations. The passkey credential that authorizes the wallet lives on the user's device and nowhere else.

## What SocketFi Can and Cannot Do

**SocketFi can:**

* Deploy wallet contracts on behalf of your application
* Route authentication challenges to the user's device
* Verify WebAuthn responses and issue sessions
* Provide recovery infrastructure when a user loses their passkey
* Help your application read wallet state and submit authorized transactions

**SocketFi cannot:**

* Sign transactions on a user's behalf
* Access, freeze, or move user assets
* Execute operations on a wallet without a valid passkey signature from the user's device
* Override wallet policies

## Users Authorize Everything

Every state-changing wallet operation requires an explicit passkey signature from the user. The wallet smart contract enforces this on-chain — authorization is not a policy layer that can be bypassed at the application level. This means:

```text theme={null}
Your application requests a transaction
  ↓
SocketFi prepares an authorization message
  ↓
User's device signs it with their passkey (Face ID, Touch ID, etc.)
  ↓
Signature is verified by the wallet contract on Soroban
  ↓
Transaction executes — or is rejected
```

If the signature is missing or invalid, the wallet contract rejects the operation. Your application code cannot bypass this.

## Wallet Address as User Identity

Because the wallet address is stable, globally unique, and owned exclusively by the user, it is the most reliable identity anchor available in your system. Use it as the canonical user identifier in your backend.

```typescript theme={null}
// After authentication, verify the session token on your backend
// to obtain the wallet address — never trust client-provided values.
const session = await socketfi.authenticate();
const token = session.socketfiAccessToken;

// Send the token to your backend; verify it server-side with verifyAuth()
// and read the wallet address from the verified payload (see below).
```

The wallet address returned by `verifyAuth()` is stable across logins, device changes, credential rotations, and account recovery. It will never change for a given user.

## Verifying Identity on Your Backend

When your frontend sends a wallet address to your backend, you must verify it server-side before trusting it. Never accept a wallet address from the client without verification — a malicious client could claim any address.

<Warning>
  Never trust a wallet address provided directly by the client. Always verify the user's session token using `verifyAuth()` on your backend, and extract the wallet address from the verified token payload. An unverified wallet address from the client could belong to any user.
</Warning>

```typescript theme={null}
// Backend: verify the session token and extract the wallet address
import { verifyAuth } from "@socketfi/server";

async function protectedRoute(req, res) {
  const token = req.headers.authorization?.replace("Bearer ", "");

  // verifyAuth returns { valid: boolean, user: { id }, wallet: { address } }
  const verified = await verifyAuth(token);

  if (!verified.valid) {
    return res.status(401).json({ error: "Unauthorized" });
  }

  // verified.wallet.address is cryptographically bound to this session
  // Use this value — not req.body.walletAddress
  const user = await db.users.findByWalletAddress(verified.wallet.address);
  return res.json({ user });
}
```

## Communicating Ownership to Users

Users often do not realize they own their wallet in the same way they would own a seed-phrase wallet. Consider surfacing this clearly in your application:

* Show the wallet address (or a truncated version) somewhere accessible in account settings
* Explain during onboarding that their assets belong to them and are protected by their passkey
* When prompting for transaction approval, reinforce that only they can authorize this action

<Tip>
  Users who understand they own their wallet are more likely to engage with recovery setup, keep their passkeys up to date, and trust your application with higher-value transactions.
</Tip>

## Developer Responsibilities

While SocketFi handles wallet infrastructure, your application is responsible for:

| Responsibility                   | Guidance                                                                                |
| -------------------------------- | --------------------------------------------------------------------------------------- |
| Storing user identity            | Use `wallet.address` from the `verifyAuth()` response                                   |
| Verifying session tokens         | Always call `verifyAuth()` on the backend; never trust client-provided values           |
| Communicating transaction intent | Show users exactly what they are authorizing before the passkey prompt                  |
| Handling authorization failures  | If the user declines the passkey prompt, surface a clear error and offer a retry path   |
| Recovery UX                      | Provide a discoverable path to account recovery so users are not permanently locked out |
