diff --git a/public/images/app-sign-in.png b/public/images/app-sign-in.png deleted file mode 100644 index abc74e88..00000000 Binary files a/public/images/app-sign-in.png and /dev/null differ diff --git a/src/common/navigation.yaml b/src/common/navigation.yaml index d9c3c975..4db9d673 100644 --- a/src/common/navigation.yaml +++ b/src/common/navigation.yaml @@ -59,19 +59,36 @@ sections: usePageTitles: true pages: - path: /tutorials/todos - - path: /tutorials/angular - - path: /tutorials/indexing - path: /tutorials/public-registry + - path: /tutorials/angular + + - title: Stacks.js References + usePageTitles: true + pages: + - external: + href: 'https://github.com/blockstack/stacks.js/tree/master/packages/auth#stacksauth' + title: auth + - external: + href: 'https://github.com/blockstack/ux/tree/master/packages/connect#stacksconnect' + title: connect + - external: + href: 'https://github.com/blockstack/stacks.js/tree/master/packages/storage#stacksstorage' + title: storage + - external: + href: 'https://github.com/blockstack/stacks.js/tree/master/packages/network#stacksnetwork' + title: network + - external: + href: 'https://github.com/blockstack/stacks.js/tree/master/packages/stacking#stacksstacking' + title: stacking + - external: + href: 'https://github.com/blockstack/stacks.js/tree/master/packages/transactions#stackstransactions' + title: transactions - - title: References + - title: Protocols usePageTitles: true pages: - - path: /references/stacks-connect - path: /references/bns - path: /references/gaia - - external: - href: 'https://blockstack.github.io/stacks.js/' - title: Stacks.js - path: /start-mining - path: /references diff --git a/src/pages/build-apps/guides/authentication.md b/src/pages/build-apps/guides/authentication.md index 8ce6e188..a8e7c191 100644 --- a/src/pages/build-apps/guides/authentication.md +++ b/src/pages/build-apps/guides/authentication.md @@ -11,7 +11,7 @@ images: ## Introduction -This guide explains how to authenticate users with [the Stacks Connect protocol](/build-apps/references/stacks-connect) by implementing the `connect` package of [Stacks.js](https://blockstack.github.io/stacks.js/). +This guide explains how to authenticate users with the [`connect`](https://github.com/blockstack/ux/tree/master/packages/connect#stacksconnect) package of Stacks.js. Authentication provides a way for users to identify themselves to an app while retaining complete control over their credentials and personal details. It can be integrated alone or used in conjunction with [transaction signing](/build-apps/tutorials/transaction-signing) and [data storage](/build-apps/tutorials/data-storage), for which it is a prerequisite. @@ -19,8 +19,64 @@ Users who register for your app can subsequently authenticate to any other app w See [the Todos app tutorial](/build-apps/tutorials/todos) for a concrete example of this functionality in practice. +## How it works + +The authentication flow with Stacks is similar to the typical client-server flow used by centralized sign in services (for example, OAuth). However, with Stacks the authentication flow happens entirely client-side. + +An app and authenticator, such as [the Stacks Wallet](https://blockstack.org/wallet), communicate during the authentication flow by passing back and forth two tokens. The requesting app sends the authenticator an `authRequest` token. Once a user approves authentication, the authenticator responds to the app with an `authResponse` token. + +These tokens are are based on [a JSON Web Token (JWT) standard](https://tools.ietf.org/html/rfc7519) with additional support for the `secp256k1` curve used by Bitcoin and many other cryptocurrencies. They are passed via URL query strings. + +See the [`authRequest`](#authrequest-payload-schema) and [`authResponse`](#authresponse-payload-schema) payload schemas below for more details about what data they contain. + +When a user chooses to authenticate an app, it sends the `authRequest` token to the authenticator via a URL query string with an equally named parameter: + +`https://wallet.hiro.so/...?authRequest=j902120cn829n1jnvoa...` + +When the authenticator receives the request, it generates an `authResponse` token for the app using an _ephemeral transit key_ . The ephemeral transit key is just used for the particular instance of the app, in this case, to sign the `authRequest`. + +The app stores the ephemeral transit key during request generation. The public portion of the transit key is passed in the `authRequest` token. The authenticator uses the public portion of the key to encrypt an _app private key_ which is returned via the `authResponse`. + +The authenticator generates the app private key from the user's _identity address private key_ and the app's domain. The app private key serves three functions: + +1. It is used to create credentials that give the app access to a storage bucket in the user's Gaia hub +2. It is used in the end-to-end encryption of files stored for the app in the user's Gaia storage. +3. It serves as a cryptographic secret that apps can use to perform other cryptographic functions. + +Finally, the app private key is deterministic, meaning that the same private key will always be generated for a given Stacks address and domain. + +The first two of these functions are particularly relevant to [data storage with Stacks.js](/build-apps/guides/data-storage). + +[Learn more about keypairs](#key-pairs) used by authentication. + +## Initiate userSession object + +Apps keep track of user authentication state with the `userSession` object, initiated with the `UserSession` and `AppConfig` classes: + +```js +import { AppConfig, UserSession } from '@stacks/connect'; + +const appConfig = new AppConfig(['store_write', 'publish_data']); +const userSession = new UserSession({ appConfig }); +``` + +The main thing to decide here is what permission scopes your app needs from the user during authentication. + +Apps may request any of the following scopes: + +| Scope | Definition | +| -------------- | ------------------------------------------------------------------------------- | +| `store_write` | Read and write data to the user's Gaia hub in an app-specific storage bucket. | +| `publish_data` | Publish data so other users of the app can discover and interact with the user. | + +The default scopes are `['store_write']` if no `scopes` array is provided when initializing the `appConfig` object. + +We recommend you initiate the `userSession` object just once in your app then reference it using imports where needed. + ## Initiate authentication flow +Apps prompt both new and existing users to authenticate with the `showConnect` function: + ```js import { AppConfig, UserSession, showConnect } from '@stacks/connect'; @@ -35,14 +91,29 @@ function authenticate() { }, redirectTo: '/', finished: () => { - window.location.reload(); + let userData = userSession.loadUserData(); + // Save or otherwise utilize userData post-authentication }, userSession: userSession, }); } ``` -## Handle pending sign in (still needed??) +`showConnect` triggers the display of a modal that initiates the authentication process for users, one in which they'll authenticate with a _Secret Key_ that's used to encrypt their private data. + +![Modal displayed by showConnect function](/images/todos/get-started.png) + +The `showConnect` function accepts a number of properties within a parameter object such as: + +- The app's `name` and `icon`: provided as strings comprising the `appDetails` object property. +- The `redirectTo` string: used to provide a URL to which the user should be redirected upon successful authentication. The `finished` callback serves a similar purpose by handling successful authentication within a context of a popup window. +- The `userSession` object initiated above. + +Once the user selects the button presented in this modal, they are passed to the Stacks Wallet for authenticator with the `authRequest` token as a GET parameter. From there they can confirm authentication and generate a new _Secret Key_ or Stacks identity before doing so, as needed before coming back to the app. + +## Handle pending authentication + +Unless the user has confirmed authentication within the context of a popup window, they will get redirected back to the app via the `redirectTo` address provided above, at which point the app needs to handle the pending authentication state using the `authResponse` value provided as a GET parameter: ```jsx import { AppConfig, UserSession, showConnect } from '@stacks/connect'; @@ -50,14 +121,130 @@ import { AppConfig, UserSession, showConnect } from '@stacks/connect'; const appConfig = new AppConfig(['store_write', 'publish_data']); const userSession = new UserSession({ appConfig }); -function componentDidMount() { +window.onload = function () { if (userSession.isSignInPending()) { userSession.handlePendingSignIn().then(userData => { - window.history.replaceState({}, document.title, '/'); - this.setState({ userData: userData }); + // Save or otherwise utilize userData post-authentication }); } else if (userSession.isUserSignedIn()) { - this.setState({ userData: userSession.loadUserData() }); + // Handle case in which user is already authenticated } -} +}; ``` + +The `isSignInPending` method of the `userSession` object is used to detect whether the user needs to handle a pending authentication state upon page load. + +The `handlePendingSignIn` method is then used to handle that state, returning a `userData` object with all the data needed to save the user's information into their session. + +The authenticated state can later be detected by the `isUserSignedIn` method in case any particular handling is needed then. + +~> Note that implementing `handlePendingSignIn` is especially important for supporting authentication within the context of mobile apps. + +If the user has indeed confirmed authentication in the context of a popup window, the authenticator will resolve the pending authentication state automatically with the app within the parent window. + +It will then trigger the `finished` function provided above, which can be used similarly to save the user's information into their session as retrieved with `userSession.loadUserData()`. + +## Key pairs + +Authentication with Stacks makes extensive use of public key cryptography generally and ECDSA with the `secp256k1` curve in particular. + +The following sections describe the three public-private key pairs used, including how they're generated, where they're used and to whom private keys are disclosed. + +### Transit private key + +The transit private is an ephemeral key that is used to encrypt secrets that +need to be passed from the authenticator to the app during the +authentication process. It is randomly generated by the app at the beginning of +the authentication response. + +The public key that corresponds to the transit private key is stored in a single +element array in the `public_keys` key of the authentication request token. The +authenticator encrypts secret data such as the app private key using this +public key and sends it back to the app when the user signs in to the app. The +transit private key signs the app authentication request. + +### Identity address private key + +The identity address private key is derived from the user's keychain phrase and +is the private key of the Stacks username that the user chooses to use to sign in +to the app. It is a secret owned by the user and never leaves the user's +instance of the authenticator. + +This private key signs the authentication response token for an app to indicate that the user approves sign in to that app. + +### App private key + +The app private key is an app-specific private key that is generated from the +user's identity address private key using the `domain_name` as input. It is +deterministic in that for a given Stacks username and `domain_name`, the same +private key is generated each time. + +The app private key is securely shared with the app on each authentication, encrypted by the authenticator with the transit public key. + +## authRequest Payload Schema + +```jsx +const requestPayload = { + jti, // UUID + iat, // JWT creation time in seconds + exp, // JWT expiration time in seconds + iss, // legacy decentralized identifier generated from transit key + public_keys, // single entry array with public key of transit key + domain_name, // app origin + manifest_uri, // url to manifest file - must be hosted on app origin + redirect_uri, // url to which the authenticator redirects user on auth approval - must be hosted on app origin + version, // version tuple + do_not_include_profile, // a boolean flag asking authenticator to send profile url instead of profile object + supports_hub_url, // a boolean flag indicating gaia hub support + scopes, // an array of string values indicating scopes requested by the app +}; +``` + +## authResponse Payload Schema + +```jsx +const responsePayload = { + jti, // UUID + iat, // JWT creation time in seconds + exp, // JWT expiration time in seconds + iss, // legacy decentralized identifier (string prefix + identity address) - this uniquely identifies the user + private_key, // encrypted private key payload + public_keys, // single entry array with public key + profile, // profile object or null if passed by profile_url + username, // Stacks username (if any) + core_token, // encrypted core token payload + email, // email if email scope is requested & email available + profile_url, // url to signed profile token + hubUrl, // url pointing to user's gaia hub + version, // version tuple +}; +``` + +## Decode authRequest or authResponse + +To decode a token and see what data it holds: + +1. Copy the `authRequest` or `authResponse` string from the URL during authentication. +2. Navigate to [jwt.io](https://jwt.io/). +3. Paste the full token there. + + The output should look similar to below: + + ```json + { + "jti": "f65f02db-9f42-4523-bfa9-8034d8edf459", + "iat": 1555641911, + "exp": 1555645511, + "iss": "did:btc-addr:1ANL7TNdT7TTcjVnrvauP7Mq3tjcb8TsUX", + "public_keys": ["02f08d5541bf611ded745cc15db08f4447bfa55a55a2dd555648a1de9759aea5f9"], + "domain_name": "http://localhost:8080", + "manifest_uri": "http://localhost:8080/manifest.json", + "redirect_uri": "http://localhost:8080", + "version": "1.3.1", + "do_not_include_profile": true, + "supports_hub_url": true, + "scopes": ["store_write", "publish_data"] + } + ``` + + The `iss` property is a decentralized identifier or `did`. This identifies the user and the username to the app. The specific `did` is a `btc-addr`. diff --git a/src/pages/build-apps/guides/data-storage.md b/src/pages/build-apps/guides/data-storage.md index 08ea1cf7..ba94adbf 100644 --- a/src/pages/build-apps/guides/data-storage.md +++ b/src/pages/build-apps/guides/data-storage.md @@ -11,7 +11,7 @@ images: ## Introduction -This guide explains how to save and retrieve data for users with [Gaia](/build-apps/references/gaia) by implementing the `connect` and `storage` packages of [Stacks.js](https://blockstack.github.io/stacks.js/). +This guide explains how to save and retrieve data for users with [Gaia](/build-apps/references/gaia) by implementing the [`connect`](https://github.com/blockstack/ux/tree/master/packages/connect#stacksconnect) and [`storage`](https://github.com/blockstack/ux/tree/master/packages/storage#stacksstorage) packages of Stacks.js. Data storage provides a way for users to save both public and private data off-chain while retaining complete control over it. @@ -19,6 +19,10 @@ Storing data off of the blockchain ensures that apps can provide users with high See [the Todos app tutorial](/build-apps/tutorials/todos) for a concrete example of this functionality in practice. +## Authentication + +TODO: Add indicator that authentication guide should be followed first + ## How data is stored Gaia storage is a key-value store. diff --git a/src/pages/build-apps/references/stacks-connect.md b/src/pages/build-apps/references/stacks-connect.md deleted file mode 100644 index fe7ee248..00000000 --- a/src/pages/build-apps/references/stacks-connect.md +++ /dev/null @@ -1,285 +0,0 @@ ---- -title: Stacks Connect -description: Open protocol for connecting apps built with Stacks -images: - large: /images/pages/authentication.svg - sm: /images/pages/authentication-sm.svg ---- - -Stacks Connect is an open protocol for connecting apps built with the Stacks blockchain, such as consumer apps with authenticators and wallets. - -## Authentication flow - -For an application developer, the application flow is similar to the typical client-server flow used by centralized sign in services (for example, OAuth). However, with Stacks Connect, the authentication flow happens entirely client-side. - -An app and authenticator, such as [the Stacks Wallet](https://blockstack.org/wallet), communicate during the authentication flow by passing back and forth two tokens. The requesting application sends the authenticator an `authRequest` token. Once a user approves a sign-in, the authenticator responds to the application with an `authResponse` token. These tokens are JSON Web Tokens, and they are passed via URL query strings. - -![](/images/app-sign-in.png) - -When a user chooses to authenticate a decentralized application, it calls the `doOpenAuth()` method which sends an `authRequest` to the authenticator. Stacks auth passes the token in via a URL query string in the `authRequest` parameter: - -`https://app.blockstack.org/#/sign-up?authRequest=j902120cn829n1jnvoa...` - -When the authenticator receives the request, it generates an (`authResponse`) token to the application using an _ephemeral transit key_ . The ephemeral transit key is just used for the particular instance of the application, in this case, to sign the `authRequest`. The application stores the ephemeral transit key during the request generation. The public portion of the transit key is passed in the `authRequest` token. The authenticator uses the public portion of the key to encrypt an _app-private key_ which is returned via the `authResponse`. - -During sign in, the authenticator generates the app-private key from the user's _identity-address private_ key and the application's `appDomain`. The app private key serves three functions: - -- It is used to create the credentials that give an app access to the Gaia storage bucket for that specific app. -- It is used in the end-to-end encryption of files stored for the app in the user's Gaia storage. -- It serves as a cryptographic secret that apps can use to perform other cryptographic functions. - -Finally, the app private key is deterministic, meaning that for a given user ID and domain name, the same private key is generated each time. - -## Scopes - -Scopes define the permissions requested by an app for granting during authentication. - -Apps may request any of the following scopes: - -| Scope | Definition | -| -------------- | ------------------------------------------------------------------------------------ | -| `store_write` | Read and write data to the user's Gaia hub in an app-specific storage bucket. | -| `publish_data` | Publish data so that other users of the app can discover and interact with the user. | - -The permissions scope should be specified through the [`AppConfig`](https://blockstack.github.io/stacks.js/classes/appconfig.html) -object. If no `scopes` array is provided to the `redirectToSignIn` or `makeAuthRequest` functions, the default is to request `['store_write']`. - -## Manifest file - -Decentralized apps have a manifest file. This file is based on the [W3C web app manifest specification](https://w3c.github.io/manifest/). -The following is an example manifest file. - -```json -{ - "name": "Todo App", - "start_url": "http://todos.blockstack.org", - "description": "A simple todo app build on Stacks", - "icons": [ - { - "src": "http://todos.blockstack.org/logo.png", - "sizes": "400x400", - "type": "image/png" - } - ] -} -``` - -The Stacks Wallet retrieves the manifest file from the app during the authentication process and displays the -information in it such as the app `name` and to the user during sign in. The location of the app manifest file is specific -in the authentication request token and **must** be on the same origin as the app requesting authentication. - -The manifest file **must** have [Cross-origin resource sharing (CORS) headers](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing) -that allow the manifest file to be fetched from any arbitrary source. This usually means returning a header like this: - -``` -Access-Control-Allow-Origin: * -``` - -How you implement CORS depends in part on which platform/service you use to serve your application. For example, Netlify -and Firebase have two different ways of configuring CORS. Consult your vendor documentation for more information. - -## Key pairs - -Stacks Auth makes extensive use of public key cryptography. Blockstack uses ECDSA with the `secp256k1` curve. The -following sections describe the three public-private key pairs used in the authentication process: - -- how they're generated -- where they're used -- to whom the private key is disclosed - -### Transit private key - -The transit private is an ephemeral key that is used to encrypt secrets that -need to be passed from the authenticator to the decentralized app during the -authentication process. It is randomly generated by the app at the beginning of -the authentication response. - -The public key that corresponds to the transit private key is stored in a single -element array in the `public_keys` key of the authentication request token. The -authenticator encrypts secret data such as the app private key using this -public key and sends it back to the app when the user signs in to the app. The -transit private key signs the app authentication request. - -### Identity address private key - -The identity address private key is derived from the user's keychain phrase and -is the private key of the Stacks username that the user chooses to use to sign in -to the app. It is a secret owned by the user and never leaves the user's -instance of the authenticator. - -This private key signs the authentication response token for an app to indicate that the user approves sign in to that app. - -### App private key - -The app private key is an app-specific private key that is generated from the -user's identity address private key using the `domain_name` as input. It is -deterministic in that for a given Stacks username and `domain_name`, the same -private key is generated each time. - -The app private key is securely shared with the app on each authentication, encrypted by the authenticator with the transit public key. - -## JSON Web Token signatures - -Both the `authRequest` and the `authResponse` tokens are [JSON Web Tokens](https://jwt.io/), and they are passed via URL query strings. - -Stacks authentication tokens are based on the [RFC 7519 OAuth JSON Web Token (JWT)](https://tools.ietf.org/html/rfc7519) -with additional support for the `secp256k1` curve used by Bitcoin and many other -cryptocurrencies. - -This signature algorithm is indicated by specifying `ES256K` in the token's -`alg` key, specifying that the JWT signature uses ECDSA with the secp256k1 -curve. Stacks auth provide both [JavaScript](https://github.com/blockstack/jsontokens-js) -and -[Ruby](https://github.com/blockstack/ruby-jwt-blockstack/tree/ruby-jwt-blockstack) -JWT libraries with support for this signing algorithm. - --> The Stacks JWT implementation is different from other implementations because of the underlying cryptography we employ. There are libraries in [JavaScript](https://github.com/blockstack/jsontokens-js) and [Ruby](https://github.com/blockstack/ruby-jwt-blockstack) available on the Blockstack Github to allow you to work with these tokens. - -### Example: authRequest payload schema - -```jsx -const requestPayload = { - jti, // UUID - iat, // JWT creation time in seconds - exp, // JWT expiration time in seconds - iss, // legacy decentralized identifier generated from transit key - public_keys, // single entry array with public key of transit key - domain_name, // app origin - manifest_uri, // url to manifest file - must be hosted on app origin - redirect_uri, // url to which the authenticator redirects user on auth approval - must be hosted on app origin - version, // version tuple - do_not_include_profile, // a boolean flag asking authenticator to send profile url instead of profile object - supports_hub_url, // a boolean flag indicating gaia hub support - scopes, // an array of string values indicating scopes requested by the app -}; -``` - -### Example: authResponse payload schema - -```jsx -const responsePayload = { - jti, // UUID - iat, // JWT creation time in seconds - exp, // JWT expiration time in seconds - iss, // legacy decentralized identifier (string prefix + identity address) - this uniquely identifies the user - private_key, // encrypted private key payload - public_keys, // single entry array with public key - profile, // profile object or null if passed by profile_url - username, // Stacks username (if any) - core_token, // encrypted core token payload - email, // email if email scope is requested & email available - profile_url, // url to signed profile token - hubUrl, // url pointing to user's gaia hub - version, // version tuple -}; -``` - -## Decode authRequest - -To decode the token and see what information it holds: - -1. Copy the `authRequest` string from the URL. - - - -2. Navigate to [jwt.io](https://jwt.io/). -3. Paste the full token there. - - The output should look similar to below: - - ```json - { - "jti": "f65f02db-9f42-4523-bfa9-8034d8edf459", - "iat": 1555641911, - "exp": 1555645511, - "iss": "did:btc-addr:1ANL7TNdT7TTcjVnrvauP7Mq3tjcb8TsUX", - "public_keys": ["02f08d5541bf611ded745cc15db08f4447bfa55a55a2dd555648a1de9759aea5f9"], - "domain_name": "http://localhost:8080", - "manifest_uri": "http://localhost:8080/manifest.json", - "redirect_uri": "http://localhost:8080", - "version": "1.3.1", - "do_not_include_profile": true, - "supports_hub_url": true, - "scopes": ["store_write", "publish_data"] - } - ``` - - The `iss` property is a decentralized identifier or `did`. This identifies the user and the user name to the application. The specific `did` is a `btc-addr`. - -## User profiles - -Profile data is stored using Gaia on the user's selected storage provider. An example of a `profile.json` file URL using -default provided storage: - -``` -https://gaia.blockstack.org/hub/1EeZtGNdFrVB2AgLFsZbyBCF7UTZcEWhHk/profile.json -``` - -Follow these steps to create and register a profile for a BNS username (`identifier`): - -1. Create a JSON profile object -2. Split up the profile into tokens, sign the tokens, and put them in a token file -3. Create a zone file that points to the web location of the profile token file - -```jsx -"account": [ - { - "@type": "Account", - "service": "twitter", - "identifier": "naval", - "proofType": "http", - "proofUrl": "https://twitter.com/naval/status/12345678901234567890" - } -] -``` - -## Create a profile - -```jsx -const profileOfNaval = { - '@context': 'http://schema.org/', - '@type': 'Person', - name: 'Naval Ravikant', - description: 'Co-founder of AngelList', -}; -``` - -## Sign a profile as a single token - -```jsx -import { wrapProfileToken, Person } from '@stacks/profiles'; - -const privateKey = 'e546ba96ee34220287d0c177418011addf8d71b32fb81ae8e33a1d7510fa5d0d01'; - -const person = new Person(profileOfNaval); -const token = person.toToken(privateKey); -const tokenFile = [wrapProfileToken(token)]; -``` - -## Verify an individual token - -```jsx -import { verifyProfileToken } from '@stacks/profiles'; - -try { - const decodedToken = verifyProfileToken(tokenFile[0].token, publicKey); -} catch (e) { - console.log(e); -} -``` - -## Recover a profile from a token file - -```jsx -const recoveredProfile = Person.fromToken(tokenFile, publicKey); -``` - -## Validate profile schema - -```jsx -const validationResults = Person.validateSchema(recoveredProfile); -``` - -### Transaction signing - -TBD: info on transaction signing protocol diff --git a/src/pages/build-apps/tutorials/todos.md b/src/pages/build-apps/tutorials/todos.md index f249f413..7dd0d880 100644 --- a/src/pages/build-apps/tutorials/todos.md +++ b/src/pages/build-apps/tutorials/todos.md @@ -69,10 +69,9 @@ You should see the app's landing page: ### Step 1: Choose **Get started** to start onboarding into the app. -The app displays a standardized introductory modal using -Stacks Connect. +The app displays a standardized introductory modal using the `@stacks/connect` library. -![The Stacks Connect Modal](/images/todos/get-started.png) +![Modal displayed by showConnect function](/images/todos/get-started.png) This modal is displayed using the `authenticate` function exported by the `src/auth.js` module, which organizes all Stacks resources needed for authentication in the app: @@ -109,7 +108,7 @@ export function getPerson() { } ``` -The `authenticate` function implements the `showConnect` function imported from the `@stacks/connect` library. +The `authenticate` function implements the `showConnect` function imported from the `connect` package of Stacks.js. `showConnect` triggers the display of a modal that initiates the authentication process for users, one in which they'll authenticate with a _Secret Key_ that's used to encrypt their private data.