Stellar Authentication
This guide is available on three different programming languages: Typescript, Kotlin and Flutter (Dart). You can change the shown version on each page via the buttons above.
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​
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
- TypeScript
const anchor = wallet.anchor({ homeDomain: "https://testanchor.stellar.org" });
Next, authenticate with the authKey
created earlier:
- TypeScript
const authKey = SigningKeypair.fromSecret("my secret key");
const sep10 = await anchor.sep10();
const authToken = await sep10.authenticate({ accountKp: authKey });
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)​
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
.
- TypeScript
const signer = new DomainSigner(
"https://demo-wallet-server.stellar.org/sign",
{},
);
const getAuthToken = async () => {
return anchor.sep10().authenticate({
accountKp,
walletSigner: signer,
clientDomain: "demo-wallet-server.stellar.org",
});
};
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:
- TypeScript
const signer = new DomainSigner("https://demo-wallet-server.stellar.org/sign", {
Authorization: `Bearer ${authToken}`,
});
Finally, with the approach above we define the signer and client domain per request. If you want to define it once and use it for every authentication call your application is making, you can do so via changing the configuration:
- TypeScript
const appCfg = new ApplicationConfiguration(
new DomainSigner("https://my-domain.com/sign", { ...headers }),
undefined,
"my-domain.com",
);
This is particularly useful for integrating with multiple anchors.
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:
- TOML
ACCOUNTS = [ "Authentication public key (address)" ]
VERSION = "0.1.0"
SIGNING_KEY = "Authentication public key (address)"
NETWORK_PASSPHRASE = "Test SDF Network ; September 2015"
Don't forget to change the network passphrase for Mainnet deployment.
Finally, let's add server implementation. This sample implementation uses express framework:
- 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,
});
});
You can see examples of both the wallet and server implementations here. As mentioned before, this server sample implementation doesn't have any protection against unauthorized requests, so you must add authorization checks as part of the request.