implement basic auth flow

This commit is contained in:
andrzej 2024-06-07 14:09:26 +02:00
parent 1b2f7b57e6
commit e5ad7961b3
6 changed files with 190 additions and 4 deletions

71
src/auth/auth.mts Normal file
View File

@ -0,0 +1,71 @@
import passport from 'passport'
import { Strategy as localStrategy } from 'passport-local'
import { User, encryptPwd, pwdIsValid } from '../model/model.mjs'
import { Strategy as JWTstrategy, ExtractJwt } from 'passport-jwt'
import { userDb } from '../db.mjs'
passport.use('signup', new localStrategy(
{
usernameField: 'username',
passwordField: 'password'
},
async (username, password, done) => {
console.log("signup auth strategy has begun")
try {
const encryptedPwd = await encryptPwd(password)
const user = await userDb("users").insert({ username: username, password: encryptedPwd }).returning(["username", "password"])
console.log(`user: ${user}`)
return done(null, user)
} catch (err) {
console.error(err)
done(err)
}
}))
passport.use('login',
new localStrategy(
{
usernameField: "username",
passwordField: "password",
session: false
},
async (email, password, done) => {
console.log("local strategy called")
try {
let returnedUser: Array<User> = await userDb("users").select("username", "password").where({ username: email })
const user: User = returnedUser[0]
console.log(`user: ${user}`)
if (!user || returnedUser.length === 0) {
return done(null, false, { message: "user not found" })
}
const validate: boolean = await pwdIsValid(password, user)
console.log(`isValidPassword? ${validate}`)
if (!validate) {
return done(null, false, { message: "wrong password" })
}
return done(null, user, { message: "logged in successfully" })
} catch (error) {
return done(error)
}
}
)
)
passport.use(
new JWTstrategy(
{
secretOrKey: "TOP_SECRET",
jwtFromRequest: ExtractJwt.fromAuthHeaderWithScheme('secret_token')
},
async (token, done) => {
try {
return done(null, token.user)
} catch (error) {
done(error)
}
}
)
)

28
src/db.mts Normal file
View File

@ -0,0 +1,28 @@
import knex from "knex";
export const db = knex({
client: 'sqlite3',
connection: {
filename: "./submissions"
},
useNullAsDefault: true
})
export const testDb = knex({
client: 'sqlite3',
connection: {
filename: "./test.db"
},
useNullAsDefault: true
})
export const userDb = knex({
client: "sqlite3",
connection: {
filename: "./users"
},
useNullAsDefault: true
})

View File

@ -1,10 +1,15 @@
import bodyParser from 'body-parser';
import express from 'express'; import express from 'express';
import passport from 'passport';
import { default as nonSecureRoutes } from "./routes/routes.mjs"
import { default as secureRoutes } from "./routes/secure-routes.mjs"
import "./auth/auth.mjs"
const app = express(); const app = express();
const port = 3000; const port = 3000;
app.use(passport.initialize())
app.get('/', (req, res) => { app.use(bodyParser.json())
res.send('Hello World!'); app.use("/", nonSecureRoutes)
}); app.use("/app", secureRoutes)
app.listen(port, () => { app.listen(port, () => {
return console.log(`Express is listening at http://localhost:${port}`); return console.log(`Express is listening at http://localhost:${port}`);

17
src/model/model.mts Normal file
View File

@ -0,0 +1,17 @@
import bcrypt from "bcrypt"
export interface User {
username: string;
password: string;
_id?: number;
}
export async function encryptPwd(pwd: string) {
return Promise.resolve(bcrypt.hash(pwd, 10))
}
export async function pwdIsValid(pwd: string, user: User): Promise<boolean> {
return Promise.resolve(bcrypt.compare(pwd, user.password))
}

50
src/routes/routes.mts Normal file
View File

@ -0,0 +1,50 @@
import express from "express"
import passport from "passport"
import jwt from 'jsonwebtoken';
import { User } from "../model/model.mjs";
const router = express.Router()
router.post("/signup",
passport.authenticate("signup", { session: false }),
async (req, res, next) => {
res.json({
message: "signup successful",
user: req.user
})
})
router.post(
'/login',
async (req, res, next) => {
passport.authenticate(
'login',
async (err: Error, user: User, _: any) => {
try {
if (err || !user) {
const error = new Error('An error occurred.');
return next(error);
}
req.login(
user,
{ session: false },
async (error) => {
if (error) return next(error);
const body = { _id: user._id, username: user.username };
const token = jwt.sign({ user: body }, 'TOP_SECRET', { expiresIn: "20m" });
return res.json({ token });
}
);
} catch (error) {
return next(error);
}
}
)(req, res, next);
}
);
export default router

View File

@ -0,0 +1,15 @@
import express from "express"
const router = express.Router()
router.get(
'/profile',
(req, res, next) => {
res.json({
message: "you made it to the secure route",
user: req.user,
token: req.query.secret_token,
})
}
)
export default router