begin auth cookie
This commit is contained in:
@@ -36,7 +36,7 @@ export class ScreenLogin {
|
|||||||
|
|
||||||
this.api.login(this.loginForm.value.username, this.loginForm.value.password).subscribe({
|
this.api.login(this.loginForm.value.username, this.loginForm.value.password).subscribe({
|
||||||
next: () => {
|
next: () => {
|
||||||
//this.router.navigate(['']);
|
this.router.navigate(['']);
|
||||||
},
|
},
|
||||||
error: (err) => {
|
error: (err) => {
|
||||||
this.error = err.error?.message || 'Login failed. Please try again.';
|
this.error = err.error?.message || 'Login failed. Please try again.';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Observable } from 'rxjs';
|
import { BehaviorSubject, catchError, map, Observable, of, tap } from 'rxjs';
|
||||||
import Transaction from '@model/transaction'
|
import Transaction from '@model/transaction'
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
@@ -8,6 +8,8 @@ import Transaction from '@model/transaction'
|
|||||||
})
|
})
|
||||||
export class APIService {
|
export class APIService {
|
||||||
private apiUrl = 'http://localhost:3000/api'
|
private apiUrl = 'http://localhost:3000/api'
|
||||||
|
private isAuthenticatedSubject = new BehaviorSubject<boolean>(false);
|
||||||
|
isAuthenticated$ = this.isAuthenticatedSubject.asObservable();
|
||||||
|
|
||||||
constructor(private http: HttpClient){}
|
constructor(private http: HttpClient){}
|
||||||
|
|
||||||
@@ -20,4 +22,14 @@ export class APIService {
|
|||||||
logout(): Observable<any>{
|
logout(): Observable<any>{
|
||||||
return this.http.post(this.apiUrl + '/auth/logout', {});
|
return this.http.post(this.apiUrl + '/auth/logout', {});
|
||||||
}
|
}
|
||||||
|
checkAuthStatus(): Observable<boolean> {
|
||||||
|
return this.http.get(`${this.apiUrl}/auth/status`, { withCredentials: true }).pipe(
|
||||||
|
map(() => true),
|
||||||
|
catchError(() => of(false)),
|
||||||
|
tap({
|
||||||
|
next: () => this.isAuthenticatedSubject.next(true),
|
||||||
|
error: () => this.isAuthenticatedSubject.next(false),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
19
package-lock.json
generated
19
package-lock.json
generated
@@ -10,8 +10,7 @@
|
|||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"client",
|
"client",
|
||||||
"server",
|
"server"
|
||||||
"shared"
|
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^25.3.2",
|
"@types/node": "^25.3.2",
|
||||||
@@ -4278,6 +4277,16 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/cookie-parser": {
|
||||||
|
"version": "1.4.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.10.tgz",
|
||||||
|
"integrity": "sha512-B4xqkqfZ8Wek+rCOeRxsjMS9OgvzebEzzLYw7NHYuvzb7IdxOkI0ZHGgeEBX4PUM7QGVvNSK60T3OvWj3YfBRg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/express": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/cors": {
|
"node_modules/@types/cors": {
|
||||||
"version": "2.8.19",
|
"version": "2.8.19",
|
||||||
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz",
|
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz",
|
||||||
@@ -9863,10 +9872,6 @@
|
|||||||
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
|
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/shared": {
|
|
||||||
"resolved": "shared",
|
|
||||||
"link": true
|
|
||||||
},
|
|
||||||
"node_modules/shebang-command": {
|
"node_modules/shebang-command": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||||
@@ -11304,6 +11309,7 @@
|
|||||||
"winston": "^3.19.0"
|
"winston": "^3.19.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/cookie-parser": "^1.4.10",
|
||||||
"@types/cors": "^2.8.19",
|
"@types/cors": "^2.8.19",
|
||||||
"@types/express": "^5.0.6",
|
"@types/express": "^5.0.6",
|
||||||
"@types/node": "^25.3.5",
|
"@types/node": "^25.3.5",
|
||||||
@@ -11319,6 +11325,7 @@
|
|||||||
},
|
},
|
||||||
"shared": {
|
"shared": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
|
"extraneous": true,
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"devDependencies": {}
|
"devDependencies": {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
"winston": "^3.19.0"
|
"winston": "^3.19.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/cookie-parser": "^1.4.10",
|
||||||
"@types/cors": "^2.8.19",
|
"@types/cors": "^2.8.19",
|
||||||
"@types/express": "^5.0.6",
|
"@types/express": "^5.0.6",
|
||||||
"@types/node": "^25.3.5",
|
"@types/node": "^25.3.5",
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import express, { Express, Request, Response } from "express";
|
import express, { Express, Request, Response } from "express";
|
||||||
import cors from "cors";
|
import cors from "cors";
|
||||||
|
import cookieParser from "cookie-parser";
|
||||||
import transactionsRouter from './routes/transactions';
|
import transactionsRouter from './routes/transactions';
|
||||||
import authRouter from './routes/auth';
|
import authRouter from './routes/auth';
|
||||||
import { db, testConnection } from "./util/db";
|
import { db, testConnection } from "./util/db";
|
||||||
import { logger } from "./util/logging";
|
import { logger } from "./util/logging";
|
||||||
|
|
||||||
const app: Express = express();
|
const app: Express = express();
|
||||||
app.use(cors());
|
app.use(cors({ origin: 'http://localhost:4200', credentials: true}));
|
||||||
|
app.use(cookieParser());
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
|
|
||||||
app.get("/api/health", (req: Request, res: Response) => {
|
app.get("/api/health", (req: Request, res: Response) => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import express from 'express';
|
import express, { Request } from 'express';
|
||||||
import { logger } from '../util/logging';
|
import { logger } from '../util/logging';
|
||||||
import User from '../model/user';
|
import User from '../model/user';
|
||||||
|
|
||||||
@@ -13,6 +13,16 @@ router.post('/login', async (req, res) => {
|
|||||||
//TODO hash passwords
|
//TODO hash passwords
|
||||||
//const isMatch = await bcrypt.compare(password, user.passwordHash);
|
//const isMatch = await bcrypt.compare(password, user.passwordHash);
|
||||||
if (!isMatch) return res.status(401).json({ message: 'Invalid credentials' });
|
if (!isMatch) return res.status(401).json({ message: 'Invalid credentials' });
|
||||||
|
|
||||||
|
// successfully authenticated
|
||||||
|
res.cookie('jwt', 'toekn', {
|
||||||
|
/*
|
||||||
|
httpOnly: true, // Prevent XSS
|
||||||
|
secure: true, // HTTPS only
|
||||||
|
sameSite: 'strict', // CSRF protection
|
||||||
|
*/
|
||||||
|
maxAge: 86400000, // 1 day
|
||||||
|
});
|
||||||
res.json({ message: 'Logged in successfully' });
|
res.json({ message: 'Logged in successfully' });
|
||||||
}catch (err) {
|
}catch (err) {
|
||||||
logger.error('Failed to authenticate:', err);
|
logger.error('Failed to authenticate:', err);
|
||||||
@@ -25,4 +35,18 @@ router.post('/logout', (req, res) => {
|
|||||||
res.json({ message: 'Logged out successfully' });
|
res.json({ message: 'Logged out successfully' });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.get('/status', (req, res) => {
|
||||||
|
|
||||||
|
console.log(req.cookies);
|
||||||
|
if (isAuthenticated(req)){
|
||||||
|
return res.status(200).json({authenticated: true});
|
||||||
|
}
|
||||||
|
return res.status(401).json({authenticated: false});
|
||||||
|
})
|
||||||
|
|
||||||
|
function isAuthenticated(req: Request){
|
||||||
|
// TODO check JWT
|
||||||
|
return req.cookies.jwt
|
||||||
|
}
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|||||||
Reference in New Issue
Block a user