Improve your authentication UX

Improving your authentication UX can allow for a smoother and more satisfying for returning user

Written by

James Perkins

Published on

The sign-in flow for your application is the gateway and sometimes the first impression; one of the biggest issues is the returning user. The return user often gets presented with a screen that looks similar to this:

sign in example

The problem is, what account did I use to sign up for this account? Was it Github? Was it Google? Or did I use my email? In great applications, Unkey included, account linking is used behind the scenes, which can help mitigate this issue.

What is Account linking?

Account linking allows developers to use the email provided and match that to a previously signed-up account, for example:

  1. A user signs up with a GitHub account, which has the email address james@unkey.dev
  2. The same user returns to the sign-in page and doesn’t remember, so they select Google and james@unkey.dev
  3. During the flow, the developer identifies this user has signed up before and links the account together, placing the user on the correct dashboard.

The main issue with relying only on account linking is that users potentially use different emails for accounts. For example, my GitHub primary email is my personal email, and I use my work email as my Google account. So, if I accidentally select the wrong option, I will go through the onboarding experience, which is frustrating as a user.

Adding indicator to improve the User Experience

To improve the experience futher we can add an indicator to the sign-in page to show the user the last method they used to access our application.

sign in example

How can you implement this?

If you want to see an example that implements the code we without any auth provider check out this code sandbox out.

First, we must add logic to the sign-in and sign-up flow to implement the “Last used” tag. The example below shows what a Clerk custom flow might look like and what we use at Unkey.

1const oauthSignIn = async (provider: OAuthStrategy) => {
2    if (!signInLoaded) {
3      return null;
4    }
5    try {
6      setIsLoading(provider);
7      await signIn.authenticateWithRedirect({
8        strategy: provider,
9        redirectUrl: "/auth/sso-callback",
10        redirectUrlComplete: "/apis",
11      });
12    } catch (err) {
13      console.error(err);
14      setIsLoading(null);
15      toast.error((err as Error).message);
16    }
17  };

As you can see from the example code above, we know what provider the end user is attempting to sign in with, so now we can store this and provide a UI update. The next step is implementing a hook to handle persisting and reading from local storage. We could write the hooks ourselves at Unkey. We opted to use usehook-ts, an excellent lightweight set of typesafe hooks with a small bundle size.

1npm install usehook-ts

Now, we can write our function.

1"use client";
2import { useLocalStorage } from "usehook-ts";
3
4export function useLastUsed() {
5  return useLocalStorage<"github" | "google" | "email" | undefined>("last_unkey_login", undefined);
6}

This function allows us to read and write our sign-in options to local storage. I will show how it is used in a second, but first, we need a UI element to show to the user. We opted for a simple text span displaying the last used, but you could display an icon or any text you prefer.

1export const LastUsed: React.FC = () => {
2  return <span className="absolute right-4 text-xs text-content-subtle">Last used</span>;
3};

Now, we have all the elements to show our end users what sign-in method they used previously. To do this, we can update our sign-in code to include the hook similar to setState

1const [lastUsed, setLastUsed] = useLastUsed();
2
3const oauthSignIn = async (provider: OAuthStrategy) => {
4    if (!signInLoaded) {
5      return null;
6    }
7    try {
8      setIsLoading(provider);
9      await signIn.authenticateWithRedirect({
10        strategy: provider,
11        redirectUrl: "/auth/sso-callback",
12        redirectUrlComplete: "/apis",
13      });
14      setLastUsed(provider === "oauth_google" ? "google" : "github");
15    } catch (err) {
16      console.error(err);
17      setIsLoading(null);
18      toast.error((err as Error).message);
19    }
20
21  };

The final step is to show the user that it was the “last used.” Below is how we implemented it at Unkey: we placed it next to the button.

1<OAuthButton onClick={() => oauthSignIn("oauth_google")}>
2  {isLoading === "oauth_google" ? (
3    <Loading className="w-6 h-6" />
4    ) : (
5       <Google className="w-6 h-6" />
6    )}
7  Google {lastUsed === "google" ? <LastUsed /> : null}
8</OAuthButton>

In conclusion, improving the authentication user experience is crucial for ensuring a smooth and hassle-free sign-in process for returning users. By implementing account linking and adding a "last used" feature, we can address the issue of users potentially using different emails for their accounts and minimize the frustration of going through the onboarding experience multiple times.

sign in example

These improvements benefit the end users and contribute to the application's success by creating a positive first impression and increasing user satisfaction. If you'd like to check out the full implementation you can find it in the Unkey repository.

Protect your API.
Start today.

2500 verifications and 100K successful rate‑limited requests per month. No CC required.