# External Wallet Authentication

Authenticate users with an Ethereum wallet they already own — MetaMask, Coinbase Wallet, WalletConnect, and others — using the [Sign-In with Ethereum (SIWE)](https://eips.ethereum.org/EIPS/eip-4361) standard. This suits crypto-native users who'd rather prove ownership of a wallet than create an email/password account.

The flow is three steps:

1. **Initialize** — `initSIWE` returns a `nonce` for the user's address.
2. **Sign** — the user signs the SIWE message with their external wallet.
3. **Authenticate** — `authenticateWithSIWE` verifies the signature and starts the Openfort session.

:::note
You bring your own wallet-connection layer (a WalletConnect SDK, MetaMask's mobile SDK, deep links, and so on) to produce the signature. Openfort handles the nonce, verification, and session — not the wallet connection itself.
:::

## 1. Initialize SIWE

```swift
import OpenfortSwift

func initializeSIWE(walletAddress: String) async throws -> OFSIWEInitResponse? {
    let result = try await OFSDK.shared.initSIWE(
        params: OFInitSIWEParams(address: walletAddress)
    )
    if let siwe = result {
        print("SIWE initialized — address: \(siwe.address), nonce: \(siwe.nonce)")
    }
    return result
}
```

#### Parameters & return

```swift
public struct OFInitSIWEParams: OFCodableSendable {
    public let address: String
}

public struct OFSIWEInitResponse: OFCodableSendable {
    public let address: String
    public let nonce: String
}
```

## 2. Get the signature from the wallet

Build the SIWE message (incorporating the `nonce` from step 1) and have the connected external wallet sign it. The exact call depends on your wallet SDK — here it's abstracted as `signWithExternalWallet`:

```swift
let signature = try await signWithExternalWallet(siweMessage)
```

:::tip
This is the user's **external** wallet signing — not the Openfort embedded wallet. Don't use `OFSDK.shared.signMessage` here; that signs with the embedded wallet, which is what you're authenticating *into*.
:::

## 3. Authenticate

Verify the signature to complete sign-in. `walletClientType` and `connectorType` describe which wallet was used (useful for analytics and reconnection):

```swift
struct WalletConnectorInfo: Identifiable {
    let id: String
    let name: String          // e.g. "MetaMask"
    let type: WalletConnector  // e.g. .metaMask
}

enum WalletConnector: String, CaseIterable, Identifiable {
    case metaMask, coinbase, walletConnect
    var id: String { rawValue }
}

func authenticate(
    signature: String,
    message: String,
    wallet: WalletConnectorInfo
) async throws -> OFAuthResponse? {
    try await OFSDK.shared.authenticateWithSIWE(
        params: OFAuthenticateWithSIWEParams(
            signature: signature,
            message: message,
            walletClientType: wallet.name,
            connectorType: wallet.type.rawValue
        )
    )
}
```

#### Parameters

```swift
public struct OFAuthenticateWithSIWEParams: OFCodableSendable {
    public let signature: String
    public let message: String
    public let walletClientType: String // e.g. "MetaMask"
    public let connectorType: String    // e.g. "metaMask"
}
```

#### Returns

Returns [`OFAuthResponse`](/docs/products/embedded-wallet/authentication#response-types).

## Linking a wallet to an existing account

To attach an external wallet to a user who's **already signed in** (rather than logging in with it), use the link variants instead: `initLinkSiwe` to get the nonce, then `linkWithSiwe` with the signature. Both mirror the auth flow above.

## Next steps

* [Configure the embedded wallet](/docs/products/embedded-wallet/swift/wallet/recovery) after authentication
* See all [authentication methods & response types](/docs/products/embedded-wallet/authentication)
