-
Notifications
You must be signed in to change notification settings - Fork 445
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Auth app #331
Open
ericamechler
wants to merge
25
commits into
Technigo:master
Choose a base branch
from
ericamechler:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Auth app #331
Changes from all commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
799bce2
removed pull-request template and instructions-file
ericamechler b503ac2
added registrations-endpoint, sign-in-endpoint & my-pages-endpointas …
ericamechler a70e35f
added expresslist-endpoints
ericamechler dadc9bb
added components-structure
ericamechler 3e3e47e
added functioning registration-form
ericamechler 0a7502b
added signin-form & loading-state
ericamechler a9241dd
added isRegistering-state to show register button
ericamechler b0d733f
Replaced button with a tag text and added styling.
JohannaBN 4578185
Updated backend endpoint /sign-in to also include the users name in t…
JohannaBN b7f5282
Added a user state to handle user information and showing it on MyPag…
JohannaBN ad6ecc2
implemented the authenticated content page
ericamechler 0a44d15
Added loading state to sign in and register form.
JohannaBN 230bd99
Added signout button and sign out function.
JohannaBN b19ab74
fixed some things with localstorage, can now refresh without being lo…
ericamechler 19fd5e6
Merge pull request #1 from ericamechler/localstorage
ericamechler c51514d
added validation rules in the model and handled logic for password-re…
ericamechler f2b85fa
added netlify & render links to readme
ericamechler 16a0415
Show loader animation when signing in and registering
FridaMari c22a34a
fixed so that after a user registers, it comes to the signin-page aut…
ericamechler ae51937
Merge pull request #2 from ericamechler/registerbug
ericamechler 9836c78
Updated Readme.
JohannaBN 7127caf
Merge pull request #3 from ericamechler/readme
JohannaBN e80db81
Added readme
JohannaBN 14d5ceb
Merge pull request #4 from ericamechler/readme-update
JohannaBN 5bc32f8
removed comments etc to clean up
ericamechler File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
cache |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,14 @@ | ||
# Project Auth API | ||
|
||
Replace this readme with your own information about your project. | ||
|
||
Start by briefly describing the assignment in a sentence or two. Keep it short and to the point. | ||
This project, completed as part of the Technigo bootcamp, involves developing a full-stack authentication system with a backend API and a React frontend. The project includes user registration and login functionalities, token-based authentication, and protected routes that require valid authentication tokens for access. | ||
|
||
## The problem | ||
|
||
Describe how you approached to problem, and what tools and techniques you used to solve it. How did you plan? What technologies did you use? If you had more time, what would be next? | ||
The goal of this project was to create a secure user authentication system. The system allows users to register and log in, storing their credentials securely. Once logged in, users can access protected content that is only available to authenticated users. The primary challenge was ensuring the security of user data and tokens while providing a seamless user experience. | ||
|
||
To create a secure user authentication system with a backend API and a React frontend, we planned the project by outlining the essential components and their interactions. The approach involved building a Node.js and Express backend with MongoDB for data storage, and bcrypt for password hashing. The frontend was developed using React, incorporating forms for user registration and login, with authenticated routes to manage secure content access. If given more time, we would enhance the validation and security features, add more user functionalities, and improve the user experience with better error handling. | ||
|
||
## View it live | ||
|
||
Every project should be deployed somewhere. Be sure to include the link to the deployed project so that the viewer can click around and see what it's all about. | ||
[Frontend](https://authentication-service.netlify.app/) | ||
[Backend](https://auth-s0og.onrender.com) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,67 @@ | ||
import bcrypt from "bcrypt"; | ||
import cors from "cors"; | ||
import express from "express"; | ||
import expressListEndpoints from "express-list-endpoints"; | ||
import mongoose from "mongoose"; | ||
|
||
const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/project-mongo"; | ||
const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/auth"; | ||
mongoose.connect(mongoUrl); | ||
mongoose.Promise = Promise; | ||
|
||
// Defines the port the app will run on. Defaults to 8080, but can be overridden | ||
// Create user object that has access-token. Mongoose-model | ||
// Destructure schema & model | ||
const { Schema, model } = mongoose; | ||
|
||
const userSchema = new Schema({ | ||
name: { | ||
type: String, | ||
unique: true, | ||
required: [true, "Name is required"], | ||
}, | ||
email: { | ||
type: String, | ||
unique: true, | ||
required: [true, "Email is required"], | ||
match: [/.+\@.+\..+/, "Please enter a valid email address"], | ||
}, | ||
password: { | ||
type: String, | ||
required: [true, "Password is required"], | ||
minlength: [8, "Password must be at least 8 characters long"], | ||
}, | ||
accessToken: { | ||
type: String, | ||
default: () => bcrypt.genSaltSync(), | ||
}, | ||
}); | ||
|
||
const User = model("User", userSchema); | ||
|
||
const authenticateUser = async (req, res, next) => { | ||
try { | ||
const user = await User.findOne({ | ||
accessToken: req.header("Authorization"), | ||
}); | ||
if (user) { | ||
req.user = user; | ||
next(); | ||
} else { | ||
res.status(401).json({ | ||
message: "Authentication missing or invalid.", | ||
loggedOut: true, | ||
}); | ||
} | ||
} catch (err) { | ||
res | ||
.status(500) | ||
.json({ message: "Internal server error", error: err.message }); | ||
} | ||
}; | ||
|
||
// Defines the port the app will run on. Defaults to 8030, but can be overridden | ||
// when starting the server. Example command to overwrite PORT env variable value: | ||
// PORT=9000 npm start | ||
const port = process.env.PORT || 8080; | ||
const port = process.env.PORT || 8030; | ||
const app = express(); | ||
|
||
// Add middlewares to enable cors and json body parsing | ||
|
@@ -18,7 +70,70 @@ app.use(express.json()); | |
|
||
// Start defining your routes here | ||
app.get("/", (req, res) => { | ||
res.send("Hello Technigo!"); | ||
const endpoints = expressListEndpoints(app); | ||
res.json(endpoints); | ||
}); | ||
|
||
app.post("/register", async (req, res) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Code looks good! Just remember to try to name endpoints after what they return or in this case create. For example: /users |
||
try { | ||
const { name, email, password } = req.body; | ||
|
||
// check if password is empty | ||
if (!password) { | ||
return res.status(400).json({ message: "Password is required" }); | ||
} | ||
|
||
// Check if password meets minimum length req | ||
if (password.length < 8) { | ||
return res.status(400).json({ | ||
message: "Password has to be at least 8 characters long", | ||
}); | ||
} | ||
// Encrypt the password | ||
const user = await new User({ | ||
name, | ||
email, | ||
password: bcrypt.hashSync(password, 10), | ||
}).save(); | ||
|
||
res.status(201).json({ id: user._id, accessToken: user.accessToken }); | ||
} catch (err) { | ||
res | ||
.status(400) | ||
.json({ message: "Could not create user", errors: err.errors }); | ||
} | ||
}); | ||
|
||
// protect my-pages endpoint | ||
app.get("/my-pages", authenticateUser, (req, res) => { | ||
res.json({ message: "This is your personal page" }); | ||
}); | ||
|
||
// Allow the user to log in, not only register | ||
|
||
app.post("/sign-in", async (req, res) => { | ||
try { | ||
const { email, password } = req.body; | ||
if (!email || !password) { | ||
res.status(400).json({ message: "Email and password are required" }); | ||
return; | ||
} | ||
|
||
const user = await User.findOne({ email }); | ||
if (user && bcrypt.compareSync(password, user.password)) { | ||
res.json({ | ||
userId: user._id, | ||
name: user.name, | ||
accessToken: user.accessToken, | ||
}); | ||
} else { | ||
res.status(401).json({ message: "Invalid email or password" }); | ||
} | ||
} catch (err) { | ||
res | ||
.status(500) | ||
.json({ message: "Internal server error", error: err.message }); | ||
} | ||
}); | ||
|
||
// Start the server | ||
|
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,33 @@ | ||
import { useEffect, useState } from "react"; | ||
|
||
import { MyPages } from "./components/MyPages"; | ||
import { Registration } from "./components/Registration"; | ||
import { SignIn } from "./components/SignIn"; | ||
|
||
export const App = () => { | ||
return <div>Find me in src/app.jsx!</div>; | ||
const [isRegistering, setIsRegistering] = useState(false); | ||
const [user, setUser] = useState(null); | ||
|
||
useEffect(() => { | ||
// Check if user data is available in localStorage on component mount | ||
const accessToken = localStorage.getItem("accessToken"); | ||
const userName = localStorage.getItem("userName"); | ||
const userId = localStorage.getItem("userId"); | ||
|
||
if (accessToken && userName && userId) { | ||
setUser({ id: userId, name: userName }); | ||
} | ||
}, []); | ||
|
||
return ( | ||
<div className="app-container"> | ||
{user ? ( | ||
<MyPages user={user} setUser={setUser} /> | ||
) : isRegistering ? ( | ||
<Registration setIsRegistering={setIsRegistering} /> | ||
) : ( | ||
<SignIn setIsRegistering={setIsRegistering} setUser={setUser} /> | ||
)} | ||
</div> | ||
); | ||
}; |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
.loader { | ||
border: 2px solid #f3f3f3; | ||
border-top: 2px solid #000000; | ||
border-radius: 50%; | ||
width: 16px; | ||
height: 16px; | ||
animation: spin 1s linear infinite; | ||
} | ||
|
||
@keyframes spin { | ||
0% { | ||
transform: rotate(0deg); | ||
} | ||
100% { | ||
transform: rotate(360deg); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import "./Loader.css"; | ||
|
||
export const Loader = () => { | ||
return <div className="loader"></div>; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { useEffect, useState } from "react"; | ||
import { SignOut } from "./SignOut"; | ||
|
||
export const MyPages = ({ user, setUser }) => { | ||
const [message, setMessage] = useState(""); | ||
const [error, setError] = useState(""); | ||
|
||
useEffect(() => { | ||
const fetchMyPages = async () => { | ||
const accessToken = localStorage.getItem("accessToken"); | ||
if (!accessToken) { | ||
setError("No access token found. Please log in again."); | ||
return; | ||
} | ||
try { | ||
const response = await fetch( | ||
"https://auth-s0og.onrender.com/my-pages", | ||
{ | ||
headers: { | ||
Authorization: accessToken, | ||
}, | ||
} | ||
); | ||
const data = await response.json(); | ||
if (response.ok) { | ||
setMessage(data.message); | ||
} else { | ||
setError("Failed to fetch data. Please log in again"); | ||
} | ||
} catch (error) { | ||
setError("An error occurred. Please try again later"); | ||
} | ||
}; | ||
fetchMyPages(); | ||
}, []); | ||
|
||
if (error) { | ||
return ( | ||
<div className="error-container"> | ||
<p>{error}</p> | ||
</div> | ||
); | ||
} | ||
|
||
if (!message) { | ||
return ( | ||
<div className="loading-container"> | ||
<p>Loading...</p> | ||
</div> | ||
); | ||
} | ||
|
||
return ( | ||
<div className="container"> | ||
<h1>Welcome, {user.name}</h1> | ||
<p>{message}</p> | ||
<SignOut setUser={setUser} /> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
.container { | ||
background-color: white; | ||
padding: 20px; | ||
border-radius: 5px; | ||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); | ||
max-width: 400px; | ||
margin: 50px auto; | ||
font-family: Arial, sans-serif; | ||
} | ||
|
||
h1 { | ||
margin-bottom: 20px; | ||
} | ||
|
||
label { | ||
display: block; | ||
margin-bottom: 5px; | ||
} | ||
|
||
input { | ||
width: 100%; | ||
padding: 8px; | ||
margin-bottom: 10px; | ||
border: 1px solid #ccc; | ||
border-radius: 3px; | ||
} | ||
|
||
button { | ||
width: 100%; | ||
padding: 10px; | ||
background-color: #28a745; | ||
color: white; | ||
border: none; | ||
border-radius: 3px; | ||
cursor: pointer; | ||
} | ||
|
||
button:hover { | ||
background-color: #218838; | ||
} | ||
|
||
p { | ||
margin-top: 20px; | ||
text-align: center; | ||
} | ||
|
||
.login-link { | ||
color: blue; | ||
cursor: pointer; | ||
text-decoration: underline; | ||
} | ||
|
||
.register-link:hover { | ||
text-decoration: none; | ||
} | ||
|
||
.loading-container { | ||
display: flex; | ||
justify-content: center; | ||
padding: 20px; | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⭐