diff --git a/frontend/src/service/store.js b/frontend/src/service/store.js
new file mode 100644
index 000000000..fbd47fbc8
--- /dev/null
+++ b/frontend/src/service/store.js
@@ -0,0 +1,17 @@
+import { configureStore } from '@reduxjs/toolkit';
+import authSlice from '../service/user/userSlice';
+
+// The value of isAuthenticated is determined by
+// whether there is a 'token' item in the local storage.
+const preloadedState = {
+ auth: {
+ isAuthenticated: !!localStorage.getItem('token'),
+ },
+};
+
+export const store = configureStore({
+ reducer: {
+ auth: authSlice,
+ },
+ preloadedState,
+});
diff --git a/frontend/src/service/user/userApi.js b/frontend/src/service/user/userApi.js
new file mode 100644
index 000000000..459fa2f79
--- /dev/null
+++ b/frontend/src/service/user/userApi.js
@@ -0,0 +1,24 @@
+import { createAsyncThunk } from '@reduxjs/toolkit';
+
+// This async thunk dispatches actions to authenticate a user.
+export const authenticate = createAsyncThunk(
+ 'user/authenticate',
+ async ({ email, password }) => {
+ const response = await fetch('http://localhost:3001/api/v1/user/login', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ email, password }),
+ });
+
+ const data = await response.json();
+
+ if (response.ok) {
+ localStorage.setItem('token', data.body.token);
+ console.log(data.message);
+ return data;
+ } else {
+ window.alert(data.message);
+ throw new Error(data.message);
+ }
+ }
+);
diff --git a/frontend/src/service/user/userSlice.js b/frontend/src/service/user/userSlice.js
new file mode 100644
index 000000000..254e2dbe3
--- /dev/null
+++ b/frontend/src/service/user/userSlice.js
@@ -0,0 +1,21 @@
+import { createSlice } from '@reduxjs/toolkit';
+import { authenticate } from './userApi';
+
+// The authSlice reducer manages the state of the user's authentication status.
+const authSlice = createSlice({
+ name: 'auth',
+ initialState: { isAuthenticated: false },
+ reducers: {},
+ // The authenticate.fulfilled action changes the value of isAuthenticated to true.
+ extraReducers: (builder) => {
+ builder
+ .addCase(authenticate.fulfilled, (state) => {
+ state.isAuthenticated = true;
+ })
+ .addCase(authenticate.rejected, (state) => {
+ state.isAuthenticated = false;
+ });
+ },
+});
+
+export default authSlice.reducer;