-
Notifications
You must be signed in to change notification settings - Fork 124
/
sep10.mdx
262 lines (186 loc) · 8.21 KB
/
sep10.mdx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
---
title: Stellar Authentication
sidebar_position: 40
---
import { LanguageSpecific } from "@site/src/components/LanguageSpecific";
import { WalletCodeExample as CodeExample } from "@site/src/components/WalletCodeExample";
import { CodeExample as NonWalletCodeExample } from "@site/src/components/CodeExample";
import Header from "./component/header.mdx";
import GlobalClientSigner from "./component/kt/global_signer.mdx";
<Header />
Wallets connect to anchors using a standard way of authentication via the Stellar network defined by the [SEP-10] standard.
This guide will cover all ways to use SEP-10 to authenticate with an anchor.
## Creating Authentication Key
:::info Custodial wallets only
:::
First, let's create an authentication key. While you can use the same key for authentication and sending funds, it's recommended to split the responsibilities. In your application, you will have one or more fund keypairs (keypairs for the accounts that hold funds and initiate and receive transactions) and one authentication key.
The authentication key is only used for authentication purposes and doesn't need to hold any funds. Note that you don't need to create an account for this keypair either.
Go to the [Stellar Lab] and generate a keypair. The secret key must be handled securely, because it will be used for authentication.
## Basic Authentication
Let's do a basic authentication. In this example, we will use wallet SDK to create an authentication token.
First, let's create an `anchor` object to work with the anchor you are integrating with. In this example, we will be using a reference anchor implementation with the home domain `testanchor.stellar.org`
<CodeExample>
```kotlin
val anchor = wallet.anchor("https://testanchor.stellar.org")
```
```typescript
let anchor = wallet.anchor({ homeDomain: "https://testanchor.stellar.org" });
```
```dart
final anchor = wallet.anchor("testanchor.stellar.org");
```
</CodeExample>
Next, authenticate with the `authKey` created earlier:
<CodeExample>
```kotlin
val authKey = SigningKeyPair.fromSecret("my secret key")
suspend fun getAuthToken(): AuthToken {
return anchor.sep10().authenticate(authKey)
}
```
```typescript
const authKey = SigningKeypair.fromSecret("my secret key");
const sep10 = await anchor.sep10();
const authToken = await sep10.authenticate({ accountKp: authKey });
```
```dart
final authKey = SigningKeyPair.fromSecret("my secret key");
final sep10 = await anchor.sep10();
final authToken = await sep10.authenticate(authKey);
```
</CodeExample>
For non-custodial wallets, you want to use the user's private key as an `authKey`.
## Home Domain (Optional)
The home domain is the optional parameter for SEP-10 authentication, when a single auth server is shared between multiple domains. Some anchors may require you to provide this argument. The SDK automatically sets the `home_domain` parameter in all SEP-10 requests.
## Client Domain (Optional)
:::info Non-custodial wallets only
:::
:::caution
Some anchors may require the `client_domain` to always be present as part of the request, even for non-custodial wallets.
::: Client domain is used by anchors to verify the origin of user's request (which wallet this user is using?). This is particularly useful for anchors for integrating with non-custodial wallets.
Supporting `client_domain` comes in two parts, the wallet's client and the wallet's server implementations. In this setup, we will have an extra authentication key. This key will be stored remotely on the server. Using the SEP-1 info file, the anchor will be able to query this key and verify the signature. As such, the anchor would be able to confirm that the request is coming from your wallet, belonging to wallet's `client_domain`.
### Client Side
First, let's implement the client side. In this example we will connect to a remote signer that signs transactions on the endpoint `https://demo-wallet-server.stellar.org/sign` for the client domain `demo-wallet-server.stellar.org`.
<CodeExample>
```kotlin
val signer = WalletSigner.DomainSigner("https://demo-wallet-server.stellar.org/sign") {}
suspend fun getAuthToken(): AuthToken {
return anchor
.sep10()
.authenticate(userKeyPair, signer, clientDomain = "demo-wallet-server.stellar.org")
}
```
```typescript
const demoWalletSigner: WalletSigner = {
signWithClientAccount: ({ transaction, accountKp }) => {
transaction.sign(accountKp);
return transaction;
},
signWithDomainAccount: async ({
transactionXDR,
networkPassphrase,
accountKp,
}) => {
return await axios.post("https://demo-wallet-server.stellar.org/sign", {
transactionXDR,
networkPassphrase,
});
},
};
const getAuthToken = async () => {
return anchor.sep10().authenticate({
accountKp,
walletSigner: demoWalletSigner,
clientDomain: "https://demo-wallet-server.stellar.org/sign",
});
};
```
```dart
final signer = DomainSigner("https://demo-wallet-server.stellar.org/sign");
final sep10 = await anchor.sep10();
final authToken = await sep10.authenticate(userKeyPair,
clientDomainSigner: signer, clientDomain: "demo-wallet-server.stellar.org");
```
</CodeExample>
:::danger
The demo-wallet signing endpoint is not protected for anybody to use. Your production URL must be protected, otherwise anybody could impersonate your wallet's user.
:::
Let's add authentication with a bearer token. Simply update the request transformer:
<CodeExample>
```kotlin
val signer = WalletSigner.DomainSigner("https://demo-wallet-server.stellar.org/sign") { bearerAuth("token") }
```
```typescript
const demoWalletSigner: WalletSigner = {
signWithClientAccount: ({ transaction, accountKp }) => {
transaction.sign(accountKp);
return transaction;
},
signWithDomainAccount: async ({
transactionXDR,
networkPassphrase,
accountKp,
}) => {
return await axios.post(
"https://demo-wallet-server.stellar.org/sign",
{
transactionXDR,
networkPassphrase,
},
{
headers: { Authorization: `Bearer ${token}` },
},
);
},
};
```
```dart
Map<String, String> requestHeaders = {
"Authorization": "Bearer $token",
"Content-Type": "application/json"
};
var signer = DomainSigner("https://demo-wallet-server.stellar.org/sign",
requestHeaders: requestHeaders);
```
</CodeExample>
[//]: # "TODO: update after WAL-882 is completed"
<LanguageSpecific kt={<GlobalClientSigner />} />
### Server Side
Next, let's implement the server side.
First, generate a new authentication key that will be used as a `client_domain` authentication key.
Next, create a `SEP-1` toml file placed under `<your domain>/.well-known/stellar.toml` with the following content:
<NonWalletCodeExample>
```toml
ACCOUNTS = [ "Authentication public key (address)" ]
VERSION = "0.1.0"
SIGNING_KEY = "Authentication public key (address)"
NETWORK_PASSPHRASE = "Test SDF Network ; September 2015"
```
</NonWalletCodeExample>
Don't forget to change the network passphrase for Mainnet deployment.
Finally, let's add server implementation. This sample implementation uses express framework:
<NonWalletCodeExample>
```javascript
app.post("/sign", (req, res) => {
const envelope_xdr = req.body.transaction;
const network_passphrase = req.body.network_passphrase;
const transaction = new Transaction(envelope_xdr, network_passphrase);
if (Number.parseInt(transaction.sequence, 10) !== 0) {
res.status(400);
res.send("transaction sequence value must be '0'");
return;
}
transaction.sign(Keypair.fromSecret(SERVER_SIGNING_KEY));
res.set("Access-Control-Allow-Origin", "*");
res.status(200);
res.send({
transaction: transaction.toEnvelope().toXDR("base64"),
network_passphrase: network_passphrase,
});
});
```
</NonWalletCodeExample>
You can see full example [here](https://github.com/stellar/stellar-demo-wallet/blob/52071629f8d29470b61799bef9519776d9c252d2/packages/demo-wallet-server/src/index.ts). As mentioned before, this sample implementation doesn't have any protection against unauthorized requests, so you must add authorization checks as part of the request.
[sep-1]: https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0001.md
[sep-10]: https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0010.md
[stellar lab]: https://laboratory.stellar.org/