import { createRemoteJWKSet, jwtVerify, type JWTPayload } from 'jose' import { GraphQLError } from 'graphql' import type { Request } from 'express' const LOGTO_JWKS_URL = process.env.LOGTO_JWKS_URL || 'https://auth.optovia.ru/oidc/jwks' const LOGTO_ISSUER = process.env.LOGTO_ISSUER || 'https://auth.optovia.ru/oidc' const jwks = createRemoteJWKSet(new URL(LOGTO_JWKS_URL)) export interface AuthContext { userId?: string scopes: string[] isM2M?: boolean } function getBearerToken(req: Request): string | null { const auth = req.headers.authorization || '' if (!auth.startsWith('Bearer ')) return null const token = auth.slice(7) if (!token || token === 'undefined') return null return token } export async function publicContext(req: Request): Promise { // Optional auth - try to extract userId if token present const token = getBearerToken(req) if (!token) return { scopes: [] } try { const { payload } = await jwtVerify(token, jwks, { issuer: LOGTO_ISSUER }) return { userId: payload.sub, scopes: [] } } catch { return { scopes: [] } } } export async function userContext(req: Request): Promise { const token = getBearerToken(req) if (!token) { throw new GraphQLError('Unauthorized', { extensions: { code: 'UNAUTHENTICATED' } }) } const { payload } = await jwtVerify(token, jwks, { issuer: LOGTO_ISSUER }) return { userId: payload.sub, scopes: [] } } export async function m2mContext(): Promise { return { scopes: [], isM2M: true } }