Unstoppable Login without Popup
This integration guide shows you how to add Login to Unstoppable to a single-page application without the popup feature, using a TypeScript and React Router example. You will configure the application to receive the authorization tokens and metadata by following the steps below.
warning
Unstoppable Login can be integrated with any EVM-compatible DApp (as well as Solana DApps). However, domains minted on testnets (e.g. Amoy or Sepolia) are not supported.
dependencies
The example code in this guide has the following dependencies: typescript
, react
, react-router-dom
, @uauth/js
Step 1: Create Your App
Create a new React application if you don't already have one. The following commands will create a new react/typescript project in the login-without-popup
folder.
yarn create react-app login-without-popup --template typescript
npx create-react-app login-without-popup --template typescript
All example code can be added to the /src/App.tsx
file created by this step.
Step 2: Install the Libraries
For this example, we will use the UAuth library for login authentication and React Router to handle single page routing.
yarn add react-router-dom @uauth/js
npm install --save react-router-dom @uauth/js
Add the following imports to your App.tsx
.
import React, { useEffect, useState } from "react";
import {
BrowserRouter,
RouteProps,
Routes,
Route,
Navigate,
useLocation,
} from "react-router-dom";
Step 3: Configure UAuth
First, you will configure the UAuth class using the Client Metadata from your login client configuration.
import UAuth from "@uauth/js";
const uauth = new UAuth({
clientID: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
redirectUri: "http://localhost:3000/callback",
scope: "openid wallet email:optional humanity_check:optional",
});
danger
The redirect URIs used to configure this UAuth
instance must be an EXACT match to the Redirect URIs Redirect URI entered in your Login Client Configuration. See Rules for Redirect URIs for more details.
For local testing, they must also match the address and port your application is running on. For Create React App, this is localhost:3000
by default.
Step 4: Create a Login Button
Next, you will call uauth.login()
to initiate a UAuth login upon clicking the login button. Features of this method include:
- Exposes modal to allow users to input their domain.
- Queries the blockchain to find if an auth server has been configured otherwise uses fallback.
- Redirects the user to the auth server with a OIDC compliant authorization request.
-
After every authorization attempt the server will redirect the user to the
redirectUri
specified at instantiation. - Throws if any login errors happen before you are redirected to the server.
Below is an example of what a login page could look like in React.
const Login: React.FC<RouteProps> = (props) => {
const [errorMessage, setErrorMessage] = useState<string | null>(
new URLSearchParams(useLocation().search || "").get("error")
);
const handleLoginButtonClick: React.MouseEventHandler<HTMLButtonElement> = (
e
) => {
setErrorMessage(null);
uauth.login().catch((error) => {
console.error("login error:", error);
setErrorMessage("User failed to login.");
});
};
return (
<>
{errorMessage && <div>{errorMessage}</div>}
<button onClick={handleLoginButtonClick}>Unstoppable Login</button>
</>
);
};
Step 5: Create the Callback Page
On the page registered as your redirectUri
, you will call uauth.loginCallback()
on page load. It will then exchange the authorization code for access and id tokens and handle any failures along the way. Features of this method include:
- Parses authorization code found in current URI.
- Exchanges authorization code for access and id tokens.
-
Stores authorization (id and access tokens) inside cache, the default cache is
window.localStorage
. - Throws if an error occurs when logging into the server or when parsing and verifying the authorization server's response.
Below is an example of what a callback page could look like in React.
const Callback: React.FC<RouteProps> = (props) => {
const [navigateTo, setNavigateTo] = useState<string>();
useEffect(() => {
// Try to exchange authorization code for access and id tokens.
uauth
.loginCallback()
// Successfully logged and cached user in `window.localStorage`
.then((response) => {
console.log("loginCallback ->", response);
setNavigateTo("/profile");
})
// Failed to exchange authorization code for token.
.catch((error) => {
console.error("callback error:", error);
setNavigateTo("/login?error=" + error.message);
});
}, []);
if (navigateTo) {
return <Navigate to={navigateTo} />;
}
return <>Loading...</>;
};
Step 6: Create a Logout Button
Finally, you will call uauth.logout()
to handle logging out upon clicking the logout button. Features of this method include:
- Clears cache of authorization.
-
If the
postLogoutRedirectUri
is present:- Uses cached authorization to create a logout URI.
- Redirects to that URI.
-
After every logout attempt the server will redirect the user to the
postLogoutRedirectUri
specified at instantiation.
const Profile: React.FC<RouteProps> = () => {
const [user, setUser] = useState<any>();
const [loading, setLoading] = useState(false);
const [navigateTo, setNavigateTo] = useState<string>();
useEffect(() => {
uauth
.user()
.then(setUser)
.catch((error) => {
console.error("profile error:", error);
setNavigateTo("/login?error=" + error.message);
});
}, []);
const handleLogoutButtonClick: React.MouseEventHandler<HTMLButtonElement> = (
e
) => {
console.log("logging out!");
setLoading(true);
uauth.logout().catch((error) => {
console.error("profile error:", error);
setLoading(false);
});
};
if (navigateTo) {
return <Navigate to={navigateTo} />;
}
if (!user || loading) {
return <>Loading...</>;
}
return (
<>
<pre>{JSON.stringify(user, null, 2)}</pre>
<button onClick={handleLogoutButtonClick}>Logout</button>
</>
);
};
Step 7: Routing to your Login Pages
Once you have all of your pages, you will need to create routes to them for React Router. This can be returned as follows from your React App component.
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Login />} />
<Route path="callback" element={<Callback />} />
<Route path="profile" element={<Profile />} />
</Routes>
</BrowserRouter>
);
Contratulations
You now have an Unstoppable Login single-page application without the popup feature. Type yarn start
/npm start
to preview your example application with a local server.