Add new profile endpoint

Add some logging output for auth failures
This commit is contained in:
Fabian Stamm 2023-04-07 22:51:08 +02:00
parent 0453e461c9
commit e27be1374b
9 changed files with 63 additions and 18 deletions

View File

@ -1,6 +1,5 @@
{ {
"name": "@hibas123/openauth-backend", "name": "@hibas123/openauth-backend",
"version": "1.1.2",
"main": "lib/index.js", "main": "lib/index.js",
"author": "Fabian Stamm <dev@fabianstamm.de>", "author": "Fabian Stamm <dev@fabianstamm.de>",
"license": "MIT", "license": "MIT",

View File

@ -5,6 +5,7 @@ import { validateJWT } from "../../keys";
import User from "../../models/user"; import User from "../../models/user";
import Mail from "../../models/mail"; import Mail from "../../models/mail";
import { OAuthJWT } from "../../helper/jwt"; import { OAuthJWT } from "../../helper/jwt";
import Logging from "@hibas123/nodelogging";
export function GetClientAuthMiddleware( export function GetClientAuthMiddleware(
checksecret = true, checksecret = true,
@ -67,13 +68,16 @@ export function GetClientApiAuthMiddleware(permissions?: string[]) {
return async (req: Request, res: Response, next: NextFunction) => { return async (req: Request, res: Response, next: NextFunction) => {
try { try {
const invalid_err = new RequestError( const invalid_err = new RequestError(
req.__("You are not logged in or your login is expired"), req.__("Unauthorized"),
HttpStatusCode.UNAUTHORIZED HttpStatusCode.UNAUTHORIZED
); );
let token = let token =
(req.query.access_token as string) || (req.query.access_token as string) ||
(req.headers.authorization as string); (req.headers.authorization as string);
if (!token) throw invalid_err; if (!token) {
Logging.debug("No token found. Searched in query (access_token) and header (authorization)");
throw invalid_err;
}
if (token.toLowerCase().startsWith("bearer ")) if (token.toLowerCase().startsWith("bearer "))
token = token.substring(7); token = token.substring(7);
@ -82,22 +86,31 @@ export function GetClientApiAuthMiddleware(permissions?: string[]) {
try { try {
data = await validateJWT(token); data = await validateJWT(token);
} catch (err) { } catch (err) {
Logging.debug("Invalid JWT", err.message);
throw invalid_err; throw invalid_err;
} }
let user = await User.findOne({ uid: data.user }); let user = await User.findOne({ uid: data.user });
if (!user) throw invalid_err; if (!user) {
Logging.debug("User not found");
throw invalid_err;
}
let client = await Client.findOne({ client_id: data.application }); let client = await Client.findOne({ client_id: data.application });
if (!client) throw invalid_err; if (!client) {
Logging.debug("Client not found");
throw invalid_err;
}
if ( if (
permissions && permissions &&
(!data.permissions || (!data.permissions ||
!permissions.every((e) => data.permissions.indexOf(e) >= 0)) !permissions.every((e) => data.permissions.indexOf(e) >= 0))
) ) {
Logging.debug("Invalid permissions");
throw invalid_err; throw invalid_err;
}
req.user = user; req.user = user;
req.client = client; req.client = client;

View File

@ -3,8 +3,9 @@ import GetAuthRoute from "./auth";
import JWTRoute from "./jwt"; import JWTRoute from "./jwt";
import Public from "./public"; import Public from "./public";
import RefreshTokenRoute from "./refresh"; import RefreshTokenRoute from "./refresh";
import ProfileRoute from "./profile";
const OAuthRoue: Router = Router(); const OAuthRoute: Router = Router();
/** /**
* @api {post} /oauth/auth * @api {post} /oauth/auth
* @apiName OAuthAuth * @apiName OAuthAuth
@ -19,7 +20,7 @@ const OAuthRoue: Router = Router();
* @apiParam {String} state State, that will be passed to redirect_uri for client * @apiParam {String} state State, that will be passed to redirect_uri for client
* @apiParam {String} nored Deactivates the Redirect response from server and instead returns the redirect URI in JSON response * @apiParam {String} nored Deactivates the Redirect response from server and instead returns the redirect URI in JSON response
*/ */
OAuthRoue.post("/auth", GetAuthRoute(false)); OAuthRoute.post("/auth", GetAuthRoute(false));
/** /**
* @api {get} /oauth/jwt * @api {get} /oauth/jwt
@ -32,7 +33,7 @@ OAuthRoue.post("/auth", GetAuthRoute(false));
* *
* @apiSuccess {String} token The JWT that allowes the application to access the recources granted for refresh token * @apiSuccess {String} token The JWT that allowes the application to access the recources granted for refresh token
*/ */
OAuthRoue.get("/jwt", JWTRoute); OAuthRoute.get("/jwt", JWTRoute);
/** /**
* @api {get} /oauth/public * @api {get} /oauth/public
@ -43,7 +44,7 @@ OAuthRoue.get("/jwt", JWTRoute);
* *
* @apiSuccess {String} public_key The applications public_key. Used to verify JWT. * @apiSuccess {String} public_key The applications public_key. Used to verify JWT.
*/ */
OAuthRoue.get("/public", Public); OAuthRoute.get("/public", Public);
/** /**
* @api {get} /oauth/refresh * @api {get} /oauth/refresh
@ -51,7 +52,7 @@ OAuthRoue.get("/public", Public);
* *
* @apiGroup oauth * @apiGroup oauth
*/ */
OAuthRoue.get("/refresh", RefreshTokenRoute); OAuthRoute.get("/refresh", RefreshTokenRoute);
/** /**
* @api {post} /oauth/refresh * @api {post} /oauth/refresh
@ -59,5 +60,14 @@ OAuthRoue.get("/refresh", RefreshTokenRoute);
* *
* @apiGroup oauth * @apiGroup oauth
*/ */
OAuthRoue.post("/refresh", RefreshTokenRoute); OAuthRoute.post("/refresh", RefreshTokenRoute);
export default OAuthRoue;
/**
* @api {get} /oauth/profile
* @apiName OAuthProfile
*
* @apiGroup oauth
*/
OAuthRoute.get("/profile", ProfileRoute);
export default OAuthRoute;

View File

@ -0,0 +1,23 @@
import Mail from "../../models/mail";
import { GetClientApiAuthMiddleware } from "../middlewares/client";
import Stacker from "../middlewares/stacker";
import { Request, Response } from "express";
export default Stacker(GetClientApiAuthMiddleware(), async (req: Request, res) => {
let mails = await Promise.all(
req.user.mails.map((id) => Mail.findById(id))
);
let mail = mails.find((e) => e.primary) || mails[0];
res.json({
user_id: req.user.uid,
id: req.user.uid,
ID: req.user.uid,
sub: req.user.uid,
email: mail.mail,
username: req.user.username,
displayName: req.user.name,
displayNameClaim: req.user.name,
});
})

View File

@ -101,7 +101,7 @@ export default async function TestData() {
data: "IIRW2P2UJRDDO2LDIRYW4LSREZLWMOKDNBJES2LLHRREK3R6KZJQ", data: "IIRW2P2UJRDDO2LDIRYW4LSREZLWMOKDNBJES2LLHRREK3R6KZJQ",
expires: null, expires: null,
}); });
TwoFactor.save(t); await TwoFactor.save(t);
} }
let login_token = await LoginToken.findOne({ token: "test01" }); let login_token = await LoginToken.findOne({ token: "test01" });

View File

@ -63,8 +63,7 @@ export default class Web {
let m = req.method; let m = req.method;
while (m.length < 4) m += " "; while (m.length < 4) m += " ";
Logging.log( Logging.log(
`${m} ${req.originalUrl} ${ `${m} ${req.originalUrl} ${(req as any).language || ""
(req as any).language || ""
} ${resColor}${res.statusCode}\x1b[0m - ${time}ms` } ${resColor}${res.statusCode}\x1b[0m - ${time}ms`
); );
res.removeListener("finish", listener); res.removeListener("finish", listener);
@ -107,7 +106,7 @@ export default class Web {
if (error.status === 500 && !(<any>error).nolog) { if (error.status === 500 && !(<any>error).nolog) {
Logging.error(error); Logging.error(error);
} else { } else {
Logging.log("Responded with Error", error.status); Logging.log("Responded with Error", error.status, error.message);
} }
if (req.accepts(["json"])) { if (req.accepts(["json"])) {

1
Frontend Submodule

@ -0,0 +1 @@
Subproject commit 8ed18a9695b38418b118c1b60845b001b2bca8d3

View File

@ -1,6 +1,5 @@
{ {
"name": "@hibas123/openauth-views-v1", "name": "@hibas123/openauth-views-v1",
"version": "1.0.0",
"main": "index.js", "main": "index.js",
"author": "Fabian Stamm <dev@fabianstamm.de>", "author": "Fabian Stamm <dev@fabianstamm.de>",
"license": "MIT", "license": "MIT",

View File

@ -1,5 +1,6 @@
{ {
"name": "@hibas123/openauth", "name": "@hibas123/openauth",
"version": "1.2.0",
"author": "Fabian Stamm <dev@fabianstamm.de>", "author": "Fabian Stamm <dev@fabianstamm.de>",
"private": true, "private": true,
"scripts": { "scripts": {