Skip to main content

Authentication

In this section we add Login, Logout, and SignUp for out website.

note

Next steps of this tutorial require a logged-in user.

1. Create Login, Logout, and SignUp hooks

These hooks are wrappers around ReactSDK hooks. They handle the logic of authentication, and we handle the behavior of our application. We use localStorage to store the apiKey.

import {useLogin as useReactSDKLogin} from "@tribeplatform/react-sdk/hooks";
import {useCallback} from "react";

export const useLogin = () => {
const {login} = useReactSDKLogin()

return useCallback((email: string, password: string) => {
login({
variables: {input: {usernameOrEmail: email, password}}
}
).then((token) => {
localStorage.setItem('apiKey', token.accessToken)
window.location.href = '/react-sdk-tutorial'
})
}, [login])
}

2. Create Login and SignUp pages

We use the hooks above to create simple Login and SignUp pages.

import {useState} from "react";
import {useLogin} from "../hooks/useLogin";

export const Login = () => {
const [email, setEmail] = useState<string>('')
const [password, setPassword] = useState<string>('')
const login = useLogin()

return (
<div className="w-1/2 mx-auto mt-5">
<h1 className="text-2xl mb-5">Login</h1>
<label className="block text-gray-700 text-sm font-bold mb-2">
Email
</label>
<input
className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline mb-5"
type="email" placeholder="[email protected]" onChange={event => setEmail(event.target.value)}
/>
<label className="block text-gray-700 text-sm font-bold mb-2">
Password
</label>
<input
className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline mb-5"
type="password" placeholder="********" onChange={event => setPassword(event.target.value)}
/>
<button
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded mt-5"
onClick={() => {
login(email, password)
}}
>
Login
</button>
</div>
)
}

3. Routes and Buttons

Now we need to add the authentication routes and a header to ease the flow of authentication. We use useAuthMember hook to retrieve the current authenticated user.

App.tsx
import React from 'react';
import {Routes, Route, Link} from "react-router-dom";
import NewsList from "./components/NewsList";
import {NewsPage} from "./components/NewsPage";
import {Login} from "./components/Login";
import {useLogout} from "./hooks/useLogout";
import {useAuthMember} from "@tribeplatform/react-sdk/hooks";
import {SignUp} from "./components/SignUp";

function App() {
const logout = useLogout()
const {data: user} = useAuthMember()

return (
<>
<nav className="flex justify-center lg:mt-2">
<div className="flex items-center justify-between flex-wrap lg:w-3/4 w-full p-2 bg-hacker-header">
<div className="flex items-center flex-shrink-0 text-black mr-6">
<Link to="/">
<span className="font-semibold text-xl tracking-tight">ReactSDK Tutorial</span>
</Link>
</div>
<div className="w-full block flex-grow lg:flex lg:items-center lg:w-auto text-sm">
<div className="lg:flex-grow">
<Link to="/"
className="block mt-4 lg:inline-block lg:mt-0 text-black hover:text-white mr-4">
News
</Link>
<Link to="/submit"
className="block mt-4 lg:inline-block lg:mt-0 text-black hover:text-white mr-4">
Submit
</Link>
</div>
<div>
{!user && (
<>
<Link to="/login"
className="block mt-4 lg:inline-block lg:mt-0 text-black hover:text-white mr-4">
Login
</Link>
<Link to="/signup"
className="block mt-4 lg:inline-block lg:mt-0 text-black hover:text-white mr-4">
Sign Up
</Link>
</>
)}
{user && (
<>
<span className="block mt-4 lg:inline-block lg:mt-0 text-black mr-4">
Hello, {user.name}
</span>
<div
className="block mt-4 lg:inline-block lg:mt-0 text-black hover:text-white mt-4 cursor-pointer"
onClick={() => {
logout()
}}
>
Logout
</div>
</>
)}
</div>
</div>
</div>
</nav>
<Routes>
<Route path="/" element={<NewsList/>}/>
<Route path="/login" element={<Login/>}/>
<Route path="/signup" element={<SignUp/>}/>
<Route path="/:postId" element={<NewsPage/>}/>
</Routes>
</>
);
}

export default App;

4. Modify the BettermodeProvide

The last step is to tell the BettermodeProvide to read the accessToken from the localStorage.

index.tsx
import React from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter} from "react-router-dom";
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {Provider as BettermodeProvider} from '@tribeplatform/react-sdk'

ReactDOM.render(
<React.StrictMode>
<BettermodeProvider config={{
baseUrl: 'https://api.bettermode.com',
networkDomain: 'react-sdk-tutorial.tribeplatform.com',
accessToken: localStorage.getItem('apiKey')
}}>
<BrowserRouter basename="/react-sdk-tutorial">
<App/>
</BrowserRouter>
</BettermodeProvider>
</React.StrictMode>,
document.getElementById('root')
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
info

If your community is hosted on a region other than the US region (us-east-1), you should use a different GraphQL URL (baseUrl) as stated here under the GraphQL Endpoint section.

note

You can see the final result here.