Skip to content

Commit c5c75a4

Browse files
implement JWT authentication with local storage for login
1 parent 6877fde commit c5c75a4

3 files changed

Lines changed: 66 additions & 8 deletions

File tree

client/src/lib/api.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
import axios from "axios";
22

3+
import { getAccessToken } from "./auth";
4+
5+
// use env URL to call API
36
const api = axios.create({ baseURL: process.env.NEXT_PUBLIC_BACKEND_URL });
47

8+
// for login, register interceptor to attach bearer token
9+
api.interceptors.request.use((config) => {
10+
const token = getAccessToken();
11+
if (token) {
12+
config.headers.Authorization = `Bearer ${token}`;
13+
}
14+
return config;
15+
});
16+
517
export default api;

client/src/lib/auth.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// JWT variables
2+
const ACCESS_KEY = "access_token";
3+
const REFRESH_KEY = "refresh_token";
4+
5+
// when called, import JWT variables and store them in local storage
6+
7+
// set
8+
export const setTokens = (access: string, refresh: string) => {
9+
localStorage.setItem(ACCESS_KEY, access);
10+
localStorage.setItem(REFRESH_KEY, refresh);
11+
};
12+
13+
// get
14+
export const getAccessToken = () => {
15+
return localStorage.getItem(ACCESS_KEY);
16+
};
17+
18+
// clear
19+
export const clearTokens = () => {
20+
localStorage.removeItem(ACCESS_KEY);
21+
localStorage.removeItem(REFRESH_KEY);
22+
};

client/src/pages/login.tsx

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { useState } from "react";
2+
13
import { Button } from "@/components/ui/button";
24
import {
35
Card,
@@ -8,8 +10,25 @@ import {
810
CardTitle,
911
} from "@/components/ui/card";
1012
import { Input } from "@/components/ui/input";
13+
import api from "@/lib/api";
14+
import { setTokens } from "@/lib/auth";
1115

1216
export default function Login() {
17+
// form variables
18+
const [username, setUsername] = useState("");
19+
const [password, setPassword] = useState("");
20+
21+
//function to return JWT
22+
const login = async (username: string, password: string) => {
23+
const res = await api.post("/token/", {
24+
username,
25+
password,
26+
});
27+
28+
const { access, refresh } = res.data;
29+
setTokens(access, refresh);
30+
};
31+
1332
return (
1433
<div className="flex min-h-screen items-center justify-center bg-muted">
1534
<Card className="w-full max-w-sm">
@@ -25,10 +44,11 @@ export default function Login() {
2544
<div className="flex flex-col gap-6">
2645
<div className="grid gap-2">
2746
<Input
28-
id="email"
29-
type="email"
30-
placeholder="m@example.com"
47+
id="username"
48+
type="username"
49+
placeholder="user-name"
3150
required
51+
onChange={(e) => setUsername(e.target.value)}
3252
/>
3353
</div>
3454
<div className="grid gap-2">
@@ -40,18 +60,22 @@ export default function Login() {
4060
Forgot your password?
4161
</a>
4262
</div>
43-
<Input id="password" type="password" required />
63+
<Input
64+
type="password"
65+
onChange={(e) => setPassword(e.target.value)}
66+
/>
4467
</div>
4568
</div>
4669
</form>
4770
</CardContent>
4871
<CardFooter className="flex-col gap-2">
49-
<Button type="submit" className="w-full">
72+
<Button
73+
type="submit"
74+
className="w-full"
75+
onClick={() => login(username, password)}
76+
>
5077
Login
5178
</Button>
52-
<Button variant="outline" className="w-full">
53-
Login with Google
54-
</Button>
5579
</CardFooter>
5680
</Card>
5781
</div>

0 commit comments

Comments
 (0)