User Sign In

Description of the current user sign-in flow for webar and scraper

All code for managing user auth is stored in the @shared/auth context. Any file inside this directory may import freely from other files in the directory. Files outside of shared/auth should only import from the top-level @shared/auth file.

Exported functions

The useful auth functions should be exported from @shared/auth. They are:

UserProfileButton

This component renders a button that opens the login modal if the user is signed out, and the user profile button if they are signed in. In general, this is the only component you need to worry about when adding a path for the user to log in.

useAuthWatch

This hook should be rendered in one place for every application. It sets up a Firebase watch to keep track of the current Firebase user, and load their user profile information into state. It also clears the user data when the user logs out of Firebase.

useInitializeAddressOverride

This hook should be rendered in one place for every application. It pulls an address override from localstorage.getItem("illust:addressOverride"), and uses that to override the current logged-in address. This override does not let you publish, but does let you view data as another user.

User state hooks:

  • useCurrentUser

  • useAddress

  • useIsLoadingAuth

  • useIsLoggedIn

These hooks let you get the current state of the logged-in user

authHeader

This function returns the header for an authorized request to the API

User auth flow

UserProfileButton renders LoginForm, which presents a series of buttons for a user to use to log in. Each button is associated with a different Wallet provider (Metamask, Wallet Connect, Magic Links). It also calls useLogin, which returns a login function that can be passed a provider name.

When the user clicks a login button, login uses the isLoggingIn store to set up a nonce for that login attempt. If the user clicks "Cancel" during the login, the nonce is incremented. The login promise flow periodically checks if its nonce is the current one. If it is not, it ends the login attempt and resets the login state, so the user can try logging in again.

Once the login attempt is set up, login calls getLoginCredentials, which calls a getCredentails function for the chosen provider. This function should return an ethers.js WalletProvider that is used to sign a message, and any user data returned from the provider like an email or username. It also returns a disconnect method to call after login is complete, so the wallet does not stay connected, since it is no longer needed.

login then fetches a nonce token from the API, which may only be used once, and prevents replay attacks with a signature.

The WalletProvider , token, and other credentials are then passed to loginWithFirebase, which asks the user to sign a message (that includes the nonce token) with their provider. That signature is passed to the /users/login API route, which either finds or creates a user for the address the signed the message. For new users, the address used to sign the message is stored as userProfile.addresses.eth[0]. The API then returns a Firebase Custom Token. It also sets a session cookie that the client can use to sign itself in with on other subdomains.

On the client, Firebase uses the custom token to sign in. If successful, this triggers useCurrentUser to note that the user is signed in, and fetch their user profile. Once complete, hooks like useCurrentUser will return the newly signed-in user.

Finally, the returned disconnect method for the wallet gets called, closing the connection to the wallet. At this point, the application no longer needs wallet signatures, and instead relies on Firebase to prove the user owns a wallet.

To make authorized requests to the API, the client uses authHeader to add a firebase token to the request header, and the API uses verifyAddressFromAuthToken to verify the header is valid, and the user that sent the header has access based on their address.

iuseAuthWatchuseAuthWatchuseAuthWatchuseAuthWatchuseAuthWatchuseAuthWatc

Last updated