This commit is contained in:
-24
@@ -1,7 +1,6 @@
|
|||||||
import { createRemoteJWKSet, jwtVerify, type JWTPayload } from "jose";
|
import { createRemoteJWKSet, jwtVerify, type JWTPayload } from "jose";
|
||||||
import { GraphQLError } from "graphql";
|
import { GraphQLError } from "graphql";
|
||||||
import type { FastifyRequest } from "fastify";
|
import type { FastifyRequest } from "fastify";
|
||||||
import { prisma } from "./db.js";
|
|
||||||
|
|
||||||
const LOGTO_JWKS_URL =
|
const LOGTO_JWKS_URL =
|
||||||
process.env.LOGTO_JWKS_URL || "https://auth.optovia.ru/oidc/jwks";
|
process.env.LOGTO_JWKS_URL || "https://auth.optovia.ru/oidc/jwks";
|
||||||
@@ -14,13 +13,10 @@ const jwks = createRemoteJWKSet(new URL(LOGTO_JWKS_URL));
|
|||||||
export interface AuthContext {
|
export interface AuthContext {
|
||||||
userId?: string;
|
userId?: string;
|
||||||
teamUuid?: string;
|
teamUuid?: string;
|
||||||
sessionToken?: string;
|
|
||||||
scopes: string[];
|
scopes: string[];
|
||||||
isM2M?: boolean;
|
isM2M?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SESSION_TOKEN_PREFIX = "optovia-session:";
|
|
||||||
|
|
||||||
function getBearerToken(req: FastifyRequest): string {
|
function getBearerToken(req: FastifyRequest): string {
|
||||||
const auth = req.headers.authorization || "";
|
const auth = req.headers.authorization || "";
|
||||||
if (!auth.startsWith("Bearer "))
|
if (!auth.startsWith("Bearer "))
|
||||||
@@ -75,26 +71,6 @@ function hasManagerClaim(payload: JWTPayload): boolean {
|
|||||||
export async function userContext(req: FastifyRequest): Promise<AuthContext> {
|
export async function userContext(req: FastifyRequest): Promise<AuthContext> {
|
||||||
const token = optionalBearerToken(req);
|
const token = optionalBearerToken(req);
|
||||||
if (token === null) return { scopes: [] };
|
if (token === null) return { scopes: [] };
|
||||||
if (token.startsWith(SESSION_TOKEN_PREFIX)) {
|
|
||||||
const session = await prisma.authSession.findUnique({
|
|
||||||
where: { token },
|
|
||||||
include: { user: true },
|
|
||||||
});
|
|
||||||
if (
|
|
||||||
session === null ||
|
|
||||||
session.revokedAt !== null ||
|
|
||||||
session.expiresAt <= new Date()
|
|
||||||
) {
|
|
||||||
throw new GraphQLError("Session expired", {
|
|
||||||
extensions: { code: "UNAUTHENTICATED" },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
userId: session.user.username,
|
|
||||||
sessionToken: token,
|
|
||||||
scopes: ["teams:user"],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const { payload } = await jwtVerify(token, jwks, { issuer: LOGTO_ISSUER });
|
const { payload } = await jwtVerify(token, jwks, { issuer: LOGTO_ISSUER });
|
||||||
return { userId: payload.sub, scopes: scopesFromPayload(payload) };
|
return { userId: payload.sub, scopes: scopesFromPayload(payload) };
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-6
@@ -193,12 +193,7 @@ export const userResolvers = {
|
|||||||
|
|
||||||
Mutation: {
|
Mutation: {
|
||||||
logout: async (_: unknown, __: unknown, ctx: AuthContext) => {
|
logout: async (_: unknown, __: unknown, ctx: AuthContext) => {
|
||||||
if (ctx.sessionToken !== undefined) {
|
if (!ctx.userId) throw new GraphQLError("Not authenticated");
|
||||||
await prisma.authSession.updateMany({
|
|
||||||
where: { token: ctx.sessionToken, revokedAt: null },
|
|
||||||
data: { revokedAt: new Date() },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user