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

# Recovery

> The [Sep-30] standard defines the standard way for an individual (e.g., a user or wallet) to regain access to their Stellar account after losing its private...

> [!NOTE]
>
> This guide is available on four different programming languages: Typescript, Kotlin, Flutter (Dart) and Swift. You can change the shown version on each page via the buttons above.

> [!CAUTION]
>
> **Important**
>
> Documentation for this language is currently work in progress. Some of information may not be applicable for this language, or missing. Code samples may be incomplete.

The [Sep-30] standard defines the standard way for an individual (e.g., a user or wallet) to regain access to their Stellar account after losing its private key without providing any third party control of the account. During this flow the wallet communicates with one or more recovery signer servers to register the wallet for a later recovery if it's needed.

## Create Recoverable Account

First, let's create an account key, a device key, and a recovery key that will be attached to the account.

**TypeScript**

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
const accountKp = wallet.stellar().account().createKeypair();
const deviceKp = wallet.stellar().account().createKeypair();
const recoveryKp = wallet.stellar().account().createKeypair();
```

**Kotlin**

```kotlin theme={"theme":{"light":"github-light","dark":"github-dark"}}
  val accountKp = wallet.stellar().account().createKeyPair()
  val deviceKp = wallet.stellar().account().createKeyPair()
  val recoveryKp = wallet.stellar().account().createKeyPair()
```

**Flutter**

```dart theme={"theme":{"light":"github-light","dark":"github-dark"}}
var accountKp = wallet.stellar().account().createKeyPair();
var deviceKp = wallet.stellar().account().createKeyPair();
var recoveryKp = wallet.stellar().account().createKeyPair();
```

**Swift**

```swift theme={"theme":{"light":"github-light","dark":"github-dark"}}
let accountKp = wallet.stellar.account.createKeyPair()
let deviceKp = wallet.stellar.account.createKeyPair()
let recoveryKp = wallet.stellar.account.createKeyPair()
```

The `accountKp` is the wallet's main account. The `deviceKp` we will be adding to the wallet as a signer so a device (eg. a mobile device a wallet is hosted on) can take control of the account. And the `recoveryKp` will be used to identify the key with the recovery servers.

Next, let's identify the recovery servers and create our recovery object:

**TypeScript**

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
const server1Key = "server1";
const server1 = {
  endpoint: "recovery-example.com",
  authEndpoint: "auth-example.com",
  homeDomain: "test-domain",
};

const server2Key = "server2";
const server2 = {
  endpoint: "recovery-example2.com",
  authEndpoint: "auth-example2.com",
  homeDomain: "test-domain2",
};

const recovery = wallet.recovery({
  servers: { [server1Key]: server1, [server2Key]: server2 },
});
```

**Kotlin**

```kotlin theme={"theme":{"light":"github-light","dark":"github-dark"}}
val first = RecoveryServerKey("first")
val second = RecoveryServerKey("second")
val firstServer = RecoveryServer("recovery.example.com", "auth.example.com", "example.com")
val secondServer = RecoveryServer("recovery2.example.com", "auth2.example.com", "example.com")
val servers = mapOf(first to firstServer, second to secondServer)
val recovery = wallet.recovery(servers)
```

**Flutter**

```dart theme={"theme":{"light":"github-light","dark":"github-dark"}}
var first = RecoveryServerKey("first");
var second = RecoveryServerKey("second");
var firstServer = RecoveryServer("https://recovery.example1.com", "https://auth.example1.com", "recovery.example1.com");
var secondServer = RecoveryServer("https://recovery.example2.com", "https://auth.example2.com", "recovery.example2.com");
var servers = {first:firstServer, second:secondServer};
var recovery = wallet.recovery(servers);
```

**Swift**

```swift theme={"theme":{"light":"github-light","dark":"github-dark"}}
let first = RecoveryServerKey(name: "first")
let second = RecoveryServerKey(name: "second")

let firstServer = RecoveryServer(endpoint:"https://recovery.example1.com",
                                authEndpoint:"https://auth.example1.com",
                                homeDomain:"recovery.example1.com")

let secondServer = RecoveryServer(endpoint:"https://recovery.example2.com",
                                  authEndpoint:"https://auth.example2.com",
                                  homeDomain:"recovery.example2.com")

let servers = [first: firstServer, second:secondServer]

let recovery = wallet.recovery(servers: servers)
```

Next, we need to define SEP-30 identities. In this example we are going to create an identity for both servers. Registering an identity tells the recovery server what identities are allowed to access the account.

**TypeScript**

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
const identity1 = {
  role: RecoveryRole.OWNER,
  authMethods: [
    {
      type: RecoveryType.STELLAR_ADDRESS,
      value: recoveryKp.publicKey,
    },
  ],
};

const identity2 = {
  role: RecoveryRole.OWNER,
  authMethods: [
    {
      type: RecoveryType.EMAIL,
      value: "my-email@example.com",
    },
  ],
};
```

**Kotlin**

```kotlin theme={"theme":{"light":"github-light","dark":"github-dark"}}
  val identity1 = listOf(RecoveryAccountIdentity(
        RecoveryRole.OWNER,
        listOf(RecoveryAccountAuthMethod(RecoveryType.STELLAR_ADDRESS, recoveryKp.address))
      )
    )

    val identity2 = listOf(RecoveryAccountIdentity(
        RecoveryRole.OWNER,
        listOf(RecoveryAccountAuthMethod(RecoveryType.EMAIL, "my-email@example.com"))
      )
    )
```

**Flutter**

```dart theme={"theme":{"light":"github-light","dark":"github-dark"}}
var identity1 = [
  RecoveryAccountIdentity(RecoveryRole.owner, [
    RecoveryAccountAuthMethod(RecoveryType.stellarAddress, recoveryKp.address)
  ])
];

var identity2 = [
  RecoveryAccountIdentity(RecoveryRole.owner,
      [RecoveryAccountAuthMethod(RecoveryType.email, "my-email@example.com")])
];
```

**Swift**

```swift theme={"theme":{"light":"github-light","dark":"github-dark"}}
let identity1 = [
    RecoveryAccountIdentity(role:RecoveryRole.owner,
                            authMethods: [RecoveryAccountAuthMethod(type:RecoveryType.stellarAddress,
                                                                    value:recoveryKp.address)])
]

let identity2 = [
    RecoveryAccountIdentity(role:RecoveryRole.owner,
                            authMethods: [RecoveryAccountAuthMethod(type:RecoveryType.email,
                                                                    value:"my-email@example.com")])
]
```

Here, stellar key and email are used as recovery methods. Other recovery servers may support phone as a recovery method as well.

You can read more about SEP-30 identities [here](https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0030.md#common-request-fields)

Next, let's create a recoverable account:

**TypeScript**

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
const config = {
  accountAddress: accountKp,
  deviceAddress: deviceKp,
  accountThreshold: { low: 10, medium: 10, high: 10 },
  accountIdentity: { [server1Key]: [identity1], [server2Key]: [identity2] },
  signerWeight: { device: 10, recoveryServer: 5 },
};
const recoverableWallet = await recovery.createRecoverableWallet(config);
```

**Kotlin**

```kotlin theme={"theme":{"light":"github-light","dark":"github-dark"}}
  val recoverableWallet =
    recovery.createRecoverableWallet(
      RecoverableWalletConfig(
        accountKp,
        deviceKp,
        AccountThreshold(10, 10, 10),
        mapOf(first to identity1, second to identity2),
        SignerWeight(10, 5)
      )
    )
```

**Flutter**

```dart theme={"theme":{"light":"github-light","dark":"github-dark"}}
var recoverableWallet = await recovery.createRecoverableWallet(
    RecoverableWalletConfig(
        accountKp,
        deviceKp,
        AccountThreshold(10, 10, 10),
        {first: identity1, second: identity2},
        SignerWeight(10, 5)
    )
);
```

**Swift**

```swift theme={"theme":{"light":"github-light","dark":"github-dark"}}
let config = RecoverableWalletConfig(accountAddress: accountKp,
                                    deviceAddress: deviceKp,
                                    accountThreshold: AccountThreshold(low: 10, medium: 10, high: 10),
                                    accountIdentity: [first : identity1, second: identity2],
                                    signerWeight: SignerWeight(device: 10, recoveryServer: 5))

let recoverableWallet = try await recovery.createRecoverableWallet(config: config)
```

With the given parameters, this function will create a transaction that will:

1. Set `deviceKp` as the primary account key. Please note that the master key belonging to `accountKp` will be locked. `deviceKp` should be used as a primary signer instead.
2. Set all operation thresholds to 10. You can read more about threshold in the [documentation](https://developers.stellar.org/docs/learn/fundamentals/transactions/signatures-multisig.md#thresholds)
3. Use identities that were defined earlier on both servers. (That means, both server will accept SEP-10 authentication via `recoveryKp` as an auth method)
4. Set device key weight to 10, and recovery server weight to 5. Given these account thresholds, both servers must be used to recover the account, as transaction signed by one will only have weight of 5, which is not sufficient to change account key.

Finally, sign and submit transaction to the network:

**TypeScript**

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
recoverableWallet.transaction.sign(accountKp.keypair);

await stellar.submitTransaction(recoverableWallet.transaction);
```

**Kotlin**

```kotlin theme={"theme":{"light":"github-light","dark":"github-dark"}}
  val tx = recoverableWallet.transaction.sign(accountKp)

  wallet.stellar().submitTransaction(tx)
```

**Flutter**

```dart theme={"theme":{"light":"github-light","dark":"github-dark"}}
var transaction = recoverableWallet.transaction;
transaction.sign(accountKp.keyPair, flutter_sdk.Network.TESTNET);
await wallet.stellar().submitTransaction(transaction);
```

**Swift**

```swift theme={"theme":{"light":"github-light","dark":"github-dark"}}
let transaction = recoverableWallet.transaction
try transaction.sign(keyPair: accountKp.keyPair, network: Network.testnet)
try await wallet.stellar.submitTransaction(signedTransaction: transaction)
```

## Get Account Info

You can fetch account info from one or more servers. To do so, first we need to authenticate with a recovery server using the SEP-10 authentication method:

**TypeScript**

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
const authToken = await recovery
  .sep10Auth(server1Key)
  .authenticate({ accountKp: recoveryKp });
```

**Kotlin**

```kotlin theme={"theme":{"light":"github-light","dark":"github-dark"}}
  val auth1 = recovery.sep10Auth(first).authenticate(recoveryKp)
```

**Flutter**

```dart theme={"theme":{"light":"github-light","dark":"github-dark"}}
var sep10 = await recovery.sep10Auth(first);
var authToken = await sep10.authenticate(recoveryKp);
```

**Swift**

```swift theme={"theme":{"light":"github-light","dark":"github-dark"}}
let sep10 = try await recovery.sep10Auth(key: first)
let authToken = try await sep10.authenticate(userKeyPair: recoveryKp)
```

Next, get account info using auth tokens:

**TypeScript**

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
const accountResp = await recovery.getAccountInfo(accountKp, {
  [server1Key]: authToken,
});
```

**Kotlin**

```kotlin theme={"theme":{"light":"github-light","dark":"github-dark"}}
  val accountInfo = recovery.getAccountInfo(account, mapOf(first to auth1))

  println("Recoverable info: $accountInfo")
```

**Flutter**

```dart theme={"theme":{"light":"github-light","dark":"github-dark"}}
var accountInfo = await recovery.getAccountInfo(accountKp, {first: authToken.jwt});
```

**Swift**

```swift theme={"theme":{"light":"github-light","dark":"github-dark"}}
let accountInfo = try await recovery.getAccountInfo(accountAddress: accountKp,
                                                    auth: [first:auth1Token.jwt])
```

Our second identity uses an email as an auth method. For that we can't use a \[SEP-10] auth token for that server. Instead we need to use a token that ties the email to the user. For example, Firebase tokens are a good use case for this. To use this, the recovery signer server needs to be prepared to handle these kinds of tokens.

Getting account info using these tokens is the same as before.

**TypeScript**

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
// get token from firebase
const firebaseToken = AuthToken.from(<firebase token string>)

const accountResp = await recovery.getAccountInfo(accountKp, {
  [server2Key]: firebaseToken,
});
```

**Kotlin**

```kotlin theme={"theme":{"light":"github-light","dark":"github-dark"}}
  // get token from firebase
  val firebaseToken = AuthToken.from(<firebase token string>)

  val accountInfo = recovery.getAccountInfo(account, mapOf(second to firebaseToken))

  println("Recoverable info: $accountInfo")
```

**Flutter**

```dart theme={"theme":{"light":"github-light","dark":"github-dark"}}
var accountInfo = await recovery.getAccountInfo(accountKp, {second: <other token string>});
```

**Swift**

```swift theme={"theme":{"light":"github-light","dark":"github-dark"}}
let accountInfo = try await recovery.getAccountInfo(accountAddress: accountKp,
                                                    auth: [second:<other token string>])
```

## Recover Wallet

Let's say we've lost our device key and need to recover our wallet.

First, we need to authenticate with both recovery servers:

**TypeScript**

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
const authToken1 = await recovery
  .sep10Auth(server1Key)
  .authenticate({ accountKp: recoveryKp });

// get firebase token using firebase
const firebaseToken = AuthToken.from(<firebase token string>)
```

**Kotlin**

```kotlin theme={"theme":{"light":"github-light","dark":"github-dark"}}
  val auth1 = recovery.sep10Auth(first).authenticate(recoveryKp)

  // get firebase token using firebase
  val firebaseToken = AuthToken.from(<firebase token string>)
```

**Flutter**

```dart theme={"theme":{"light":"github-light","dark":"github-dark"}}
var sep10 = await recovery.sep10Auth(first);
var authToken = await sep10.authenticate(recoveryKp);

var auth1 = authToken.jwt;
var auth2 = "..."; // get other token e.g. firebase token
```

**Swift**

```swift theme={"theme":{"light":"github-light","dark":"github-dark"}}
let sep10 = try await recovery.sep10Auth(key: first)
let authToken = try await sep10.authenticate(userKeyPair: recoveryKp)

let auth1 = authToken.jwt
let auth2 = "..."; // get other token e.g. firebase token
```

We need to know the recovery signer addresses that will be used to sign the transaction. You can get them from either the recoverable wallet object we created earlier (`recoverableWallet.signers`), or via fetching account info from recovery servers.

**TypeScript**

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
const recoverySignerAddress1 = recoverableWallet.signers[0];
const recoverySignerAddress2 = recoverableWallet.signers[1];
```

**Kotlin**

```kotlin theme={"theme":{"light":"github-light","dark":"github-dark"}}
  val recoverySigners = recoverableWallet.signers
```

**Flutter**

```dart theme={"theme":{"light":"github-light","dark":"github-dark"}}
var recoverySigners = recoverableWallet.signers;
```

**Swift**

```swift theme={"theme":{"light":"github-light","dark":"github-dark"}}
let recoverySigners = recoverableWallet.signers
```

Next, create a new device key and retrieve a signed transaction that replaces the device key:

**TypeScript**

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
const newDeviceKp = accountService.createKeypair();

const serverAuth = {
  [server1Key]: {
    signerAddress: recoverySignerAddress1,
    authToken1,
  },
  [server2Key]: {
    signerAddress: recoverySignerAddress2,
    firebaseToken,
  },
};

const recoverTxn = await recovery.replaceDeviceKey(
  accountKp,
  newDeviceKp,
  serverAuth,
);
```

**Kotlin**

```kotlin theme={"theme":{"light":"github-light","dark":"github-dark"}}
  val newKey = wallet.stellar().account().createKeyPair()

  val serverAuth = mapOf(
    first to RecoveryServerSigning(recoverySigners[0], auth1),
    second to RecoveryServerSigning(recoverySigners[1], firebaseToken)
  )

  val signedReplaceKeyTransaction =
    recovery.replaceDeviceKey(
      accountKp,
      newKey,
      serverAuth
    )
```

**Flutter**

```dart theme={"theme":{"light":"github-light","dark":"github-dark"}}
var newKey = wallet.stellar().account().createKeyPair();
var serverAuth = {
  first: RecoveryServerSigning(recoverySigners[0], auth1),
  second: RecoveryServerSigning(recoverySigners[1], auth2)
};

var signedReplaceKeyTx = await recovery.replaceDeviceKey(accountKp, newKey, serverAuth);
```

**Swift**

```swift theme={"theme":{"light":"github-light","dark":"github-dark"}}
let newKey = wallet.stellar.account.createKeyPair()
let serverAuth = [
    first: RecoveryServerSigning(signerAddress: recoverySigners[0] , authToken: auth1),
    second: RecoveryServerSigning(signerAddress: recoverySigners[1] , authToken: auth2),
]

let signedReplaceKeyTx = try await recovery.replaceDeviceKey(account: accountKp,
                                                             newKey: newKey,
                                                             serverAuth: serverAuth)
```

Calling this function will create a transaction that locks the previous device key and replaces it with your new key (having the same weight as the old one). Both recovery signers will have signed the transaction.

The lost device key is deduced automatically if not given. A signer will be considered a device key, if one of these conditions matches:

1. It's the only signer that's not in `serverAuth`.
2. All signers in `serverAuth` have the same weight, and the potential signer is the only one with a different weight.

> [!NOTE]
>
> The account created above will match the first criteria. If a 2-3 schema were used, then the second criteria would match. (In a 2-3 schema, 3 servers are used and 2 of them are enough to recover the key. This is a recommended approach.)
>
> You can also use more low-level `signWithRecoveryServers` functions to sign arbitrary transactions.

Finally, it's time to submit the transaction:

**TypeScript**

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
await stellar.submitTransaction(recoverTxn);
```

**Kotlin**

```kotlin theme={"theme":{"light":"github-light","dark":"github-dark"}}
  wallet.stellar().submitTransaction(signedReplaceKeyTransaction)
```

**Flutter**

```dart theme={"theme":{"light":"github-light","dark":"github-dark"}}
await wallet.stellar().submitTransaction(signedReplaceKeyTx);
```

**Swift**

```swift theme={"theme":{"light":"github-light","dark":"github-dark"}}
try await wallet.stellar.submitTransaction(signedTransaction: signedReplaceKeyTx)
```

[sep-30]: https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0030.md
