Your subscription could not be saved. Please try again.
Thanks for subscribing.
In traditional applications, users are required to sign-in so providers can verify and manage data on their behalf. On Stacks, users retain complete control over their personal information and credentials, which introduces changes to the authentication flow you may be familiar with.
Here, authentication refers to an information exchange between a user’s authenticator and an application a user wishes to interact with. Typically, applications need some knowledge about their users. For example, a DeFi protocol needs to know about the assets a user holds in their authenticator, and a writing app needs to connect users with the notes they’ve taken in the past. Let’s take a look at how it works.
On the surface, the authentication flow on Stacks is similar to the typical client-server flow used by centralized sign-in services. The key difference is that authentication occurs entirely client-side; no user information needs to be passed to a server.
In this authentication flow, you have two parties: an app and an authenticator (aka wallet or agent of the user, like the Hiro Wallet). In order to verify the user’s identity, these two parties pass two tokens back and forth to authenticate the user.
Those tokens are passed back and forth via a URL query string.
First, an app creates an ephemeral transit key, for the sole purpose of the authentication. The public part of this ephemeral transit key is passed to the authenticator within the authRequest token.
The authenticator then uses the received public key (of the ephemeral transit key) to encrypt an app private key, which is returned in the authResponse token. The app private key is generated from the user’s private key and from the app’s domain. This key is deterministic, meaning the key will always be the same for a given Stacks address and app domain.
Once the authResponse token is sent back, the app should have all necessary information to perform its services. This whole communication using tokens might sound complicated but is completely handled by the functions provided in the Stacks.js libraries.
Apps can obtain this information, as well as the current authentication state of a user, through the userSession object.
Before we start to authenticate, it’s important to determine the correct permissions your app needs from a user and configure them using the appConfig object. You can request any of the following permission scopes:
Creating a new AppConfig() without providing permission scopes will default to only the store_write scope.
To prompt new and existing users to authenticate, you can use the showConnect function:
Calling this function (e.g. via a button’s onclick) from the app triggers the Hiro Wallet (or another authenticator), prompting them to go through the authentication flow. From there, the user can generate a new address if needed or select an existing one before returning to the app. As you can see in the code above, the function also allows you to pass through a few properties to customize the appearance of the modal, including:
The authentication modal ultimately looks something like:
We created the connect package in Stacks.js, to make implementing authentication a straightforward and easy process for app developers. I hope this overview was helpful for those looking to gain an understanding of how it works. To learn more about user authentication, read our documentation for additional details. Happy coding!