Skip to content
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

Project Auth - Moonlight Flamingos #335

Open
wants to merge 37 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
f546254
adding the env file to gitignore in the backend
linda-f May 21, 2024
402e689
adding the vite build to netlify.toml
linda-f May 21, 2024
e2831ea
changing the browser title and icon
linda-f May 21, 2024
55ad8e8
adding basic styling in the frontend
linda-f May 21, 2024
d026eee
adding endpoints in backend and building schema
linda-f May 21, 2024
208051b
trying login endpoint having some errors
linda-f May 21, 2024
c955bd1
adding comment for reference
linda-f May 21, 2024
8671d0d
fixing login endpoint
linda-f May 23, 2024
e348afe
adding endpoint and finishing backend
linda-f May 23, 2024
3c60653
working on frontend functionality
linda-f May 23, 2024
c24be76
adding signup form to the frontend
linda-f May 23, 2024
39d0d09
adding dotenv
linda-f May 23, 2024
5fc7438
register user to backend database
linda-f May 23, 2024
2356452
added style base
Izzibizz May 23, 2024
9240ba3
Started on Login feature
Martin-Joensson May 24, 2024
2137162
Seperated registration and sign in
Martin-Joensson May 24, 2024
10762d2
Added toggle to access login or registration form
Martin-Joensson May 24, 2024
4b0bcaf
Debugging login
Martin-Joensson May 24, 2024
1325bdd
Fixed length check on the front end
Martin-Joensson May 24, 2024
f00ef29
Registration error messages sorted
Martin-Joensson May 24, 2024
23a6758
Working on log in
Martin-Joensson May 24, 2024
958b01d
Hunted down pesky typo
Martin-Joensson May 24, 2024
968228b
Log in working
Martin-Joensson May 24, 2024
8f1cf4a
Cleaned the code
Martin-Joensson May 24, 2024
3b933d5
Functionallity done, start on responsive styling
Martin-Joensson May 24, 2024
40c8ebf
setting up basic readme
linda-f May 24, 2024
1c5285c
adding netlify link
linda-f May 24, 2024
20df209
adding endpoint description and error handling also cors integration
linda-f May 25, 2024
f88755a
adding responsivness to the whole page
linda-f May 25, 2024
0af3824
adding labels to the form for accessibility
linda-f May 25, 2024
3e9c04a
Fixed typo and weird log out behaviour
Martin-Joensson May 25, 2024
3a77684
Added username to secret content section
Martin-Joensson May 25, 2024
2a4892f
Fixed horizontal overflow
Martin-Joensson May 25, 2024
60adea5
Deleted unused verifyAccessToken
Martin-Joensson May 25, 2024
5465fd1
Error messages displayed to user
Martin-Joensson May 25, 2024
c1450c1
Added Alert animation on non-200 status responses
Martin-Joensson May 25, 2024
0b53815
Added checkmark to successful login
Martin-Joensson May 25, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# 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 was about buildig a registration form. The user should be able to sign up and then sign in with the credentials. Once signed in the user should see something that would be accessable if not logged in. This fullstack project was built in a group of three people.
We started by setting up the backend and then the frontend.

## 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?
We were having some issues with setting the frontend functionallity up since we wanted to have it pretty dry in the beginning but then in the end saw that this is making things even harder.

## 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.
Backend: https://project-auth-moonlight-flamingos.onrender.com
Frontend: https://project-auth-moonlight-flamingos.netlify.app/
8 changes: 7 additions & 1 deletion backend/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
node_modules
package-lock.json
package-lock.json
.DS_Store
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
25 changes: 25 additions & 0 deletions backend/models/userSchema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import bcrypt from "bcrypt"
import mongoose from "mongoose";

const { Schema, model } = mongoose;
const UserSchema = new Schema({
username: {
type: String,
required: true,
minlength: 4,
unique: true,
},
password: {
type: String,
required: true,
minlength: 8,
},
accessToken: {
type: String,
default: () => bcrypt.genSaltSync(),
},
});

// Username, email?, encrypted password, role?

export const User = model("User", UserSchema);
3 changes: 3 additions & 0 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@
"@babel/core": "^7.17.9",
"@babel/node": "^7.16.8",
"@babel/preset-env": "^7.16.11",
"bcrypt": "^5.1.1",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.17.3",
"express-list-endpoints": "^7.1.0",
"mongoose": "^8.0.0",
"nodemon": "^3.0.1"
}
Expand Down
142 changes: 137 additions & 5 deletions backend/server.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,156 @@
import bcrypt from "bcrypt";
import cors from "cors";
import dotenv from "dotenv";
import express from "express";
import expressListEndpoints from "express-list-endpoints";
import mongoose from "mongoose";

const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/project-mongo";
// Importing the Model
import { User } from "./models/userSchema";

// Getting the dotenv file
dotenv.config();

const mongoUrl =
process.env.MONGO_URL || "mongodb://localhost/project-authorization";
mongoose.connect(mongoUrl);
mongoose.Promise = Promise;

// Defines the port the app will run on. Defaults to 8080, 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 || 8088;
const app = express();

//Middleware to Authenticate User
const authenticateUser = async (req, res, next) => {
const user = await User.findOne({ accessToken: req.header("Authorization") });
if (user) {
req.user = user;
next();
} else {
res.status(401).json({ loggedOut: true });
}
};

// Add middlewares to enable cors and json body parsing
app.use(cors());
// Adding our frontend URL to the cors that way only that URL is allowed to make backend requests.
app.use(cors("https://project-auth-moonlight-flamingos.netlify.app/"));
app.use(express.json());

// Start defining your routes here
// API Documentation
app.get("/", (req, res) => {
res.send("Hello Technigo!");
try {
const endpoints = expressListEndpoints(app).map((endpoint) => {
if (endpoint.path === "/register") {
endpoint.query = {
description: `In this endpoint you can register a new user with a POST request. Send a username of at least four characters and a password of at least eight characters in a JSON to set up a new user.`,
};
}
if (endpoint.path === "/login") {
endpoint.query = {
description: `In this endpoint you can login in a user with a POST request. Please send the users password and username in a JSON file to log in and acces the token for the user.`,
};
}
if (endpoint.path === "/secrets") {
endpoint.query = {
description: `For this endpoint there is only the GET request available if you have a valid access token you will be able to see this endpoint otherwise not.`,
};
}
return endpoint;
});
res.status(200).json(endpoints);
} catch (err) {
console.error("The following error occured:", err);
res
.status(500)
.send(
"Sorry, this page is not available at the moment. Please try again later."
);
}
});

//Sign Up Endpoint
app.post("/register", async (req, res) => {
try {
const { username, password } = req.body;

//Check the username
if (!username) {
return res.status(400).json({ message: "Username is required" });
}

if (username.length < 4) {
return res
.status(400)
.json({ message: "Username must be at least 4 characters long" });
}

//Check the password
if (!password) {
return res.status(400).json({ message: "Password is required" });
}

if (password.length < 8) {
return res
.status(400)
.json({ message: "Password must be at least 8 characters long" });
}

//Create a User
const user = new User({
username: username,
password: bcrypt.hashSync(password, 10),
});
await user.save();
res.status(201).json({
message: "Registration Complete!",
id: user._id,
accessToken: user.accessToken,
});
} catch (err) {
res
.status(400)
.json({ message: "Could not register user.", error: err.errors });
}
});

// Login Endpoint
app.post("/login", async (req, res) => {
try {
const { username, password } = req.body;

//Find the user by username in the Database
const user = await User.findOne({ username: username });

//Compare the password of the found user
if (user) {
const isPasswordCorrect = await bcrypt.compare(password, user.password);
if (isPasswordCorrect) {
res.status(202).json({
message: "Logged in",
id: user._id,
username: user.username,
accessToken: user.accessToken,
});
} else {
res.status(401).json({ message: "This password is incorrect." });
}
} else {
res.status(404).json({ message: "User not found." });
}
} catch (err) {
res.status(500).json({
message: "Somethings wrong with the sign in. Please try again later.",
error: err.message,
});
}
});

//Secrets Endpoint
app.get("/secrets", authenticateUser);
app.get("/secrets", (req, res) => {
res.status(200).json({ secret: `Super secrets... nobody will know. Well other signed in people will know I guess...` });
});

// Start the server
Expand Down
8 changes: 0 additions & 8 deletions frontend/README.md

This file was deleted.

11 changes: 8 additions & 3 deletions frontend/index.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
<!doctype html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<link rel="icon" href="/auth.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React</title>
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Overpass:ital,wght@0,100..900;1,100..900&display=swap"
rel="stylesheet"
/>
<title>Authentication Project</title>
</head>
<body>
<div id="root"></div>
Expand Down
1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"preview": "vite preview"
},
"dependencies": {
"lottie-react": "^2.4.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
Expand Down
Binary file added frontend/public/auth.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/public/background.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
57 changes: 57 additions & 0 deletions frontend/public/crypTech.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion frontend/public/vite.svg

This file was deleted.

29 changes: 28 additions & 1 deletion frontend/src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,30 @@
import { useState } from "react";
import { Footer } from "./Footer";
import { Header } from "./Header";
import { MainSection } from "./MainSection";

export const App = () => {
return <div>Find me in src/app.jsx!</div>;
const [formSelect, setFormSelect] = useState("Sign Up");
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [isMessage, setIsMessage] = useState(false);

return (
<>
<Header
setFormSelect={setFormSelect}
isLoggedIn={isLoggedIn}
setIsLoggedIn={setIsLoggedIn}
setIsMessage={setIsMessage}
/>
<MainSection
formSelect={formSelect}
setFormSelect={setFormSelect}
isLoggedIn={isLoggedIn}
setIsLoggedIn={setIsLoggedIn}
isMessage={isMessage}
setIsMessage={setIsMessage}
/>
<Footer />
</>
);
};
38 changes: 38 additions & 0 deletions frontend/src/Components/Button.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import PropTypes from "prop-types";

export const Button = ({
action,
setFormSelect,
setIsMessage,
setIsLoggedIn,
}) => {
const handleClick = () => {
setIsMessage(false);
setFormSelect(action);

if (action === "Log Out") {
// setIsLoggedIn(false);
localStorage.clear();
setIsLoggedIn(false);
}
};

return (
<>
<button
id={action.toLowerCase().replace(/\s/g, "")}
className="buttonstyle"
onClick={handleClick}
>
{action}
</button>
</>
);
};

Button.propTypes = {
action: PropTypes.string,
setFormSelect: PropTypes.func,
setIsMessage: PropTypes.func,
setIsLoggedIn: PropTypes.func,
};
Loading