Authorize manager orders by app JWT scope

This commit is contained in:
Ruslan Bakiev
2026-05-31 22:01:00 +05:00
parent 3392bedc80
commit 6719e9faf7

View File

@@ -5,7 +5,7 @@ import type { Request } from 'express'
const LOGTO_JWKS_URL = process.env.LOGTO_JWKS_URL || 'https://auth.optovia.ru/oidc/jwks' 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 LOGTO_ISSUER = process.env.LOGTO_ISSUER || 'https://auth.optovia.ru/oidc'
const LOGTO_ORDERS_AUDIENCE = process.env.LOGTO_ORDERS_AUDIENCE || 'https://orders.optovia.ru' const LOGTO_ORDERS_AUDIENCE = process.env.LOGTO_ORDERS_AUDIENCE || 'https://orders.optovia.ru'
const MANAGER_JWT_ISSUER = 'optovia:teams' const APP_JWT_ISSUER = 'optovia:teams'
const jwks = createRemoteJWKSet(new URL(LOGTO_JWKS_URL)) const jwks = createRemoteJWKSet(new URL(LOGTO_JWKS_URL))
@@ -69,22 +69,21 @@ export async function teamContext(req: Request): Promise<AuthContext> {
} }
} }
function managerJwtSecret(): Uint8Array { function appJwtSecret(): Uint8Array {
const secret = process.env.MANAGER_JWT_SECRET const secret = process.env.APP_JWT_SECRET
if (!secret) throw new GraphQLError('MANAGER_JWT_SECRET is required', { extensions: { code: 'INTERNAL_SERVER_ERROR' } }) if (!secret) throw new GraphQLError('APP_JWT_SECRET is required', { extensions: { code: 'INTERNAL_SERVER_ERROR' } })
return new TextEncoder().encode(secret) return new TextEncoder().encode(secret)
} }
export async function managerContext(req: Request): Promise<AuthContext> { export async function managerContext(req: Request): Promise<AuthContext> {
const token = getBearerToken(req) const token = getBearerToken(req)
const { payload } = await jwtVerify(token, managerJwtSecret(), { const { payload } = await jwtVerify(token, appJwtSecret(), {
issuer: MANAGER_JWT_ISSUER, issuer: APP_JWT_ISSUER,
audience: LOGTO_ORDERS_AUDIENCE, audience: LOGTO_ORDERS_AUDIENCE,
}) })
const scopes = scopesFromPayload(payload) const scopes = scopesFromPayload(payload)
const role = (payload as Record<string, unknown>).role
const teamUuid = (payload as Record<string, unknown>).team_uuid as string | undefined const teamUuid = (payload as Record<string, unknown>).team_uuid as string | undefined
if (!payload.sub || role !== 'manager' || !scopes.includes('manager') || !teamUuid) { if (!payload.sub || !scopes.includes('manager') || !teamUuid) {
throw new GraphQLError('Unauthorized', { extensions: { code: 'UNAUTHENTICATED' } }) throw new GraphQLError('Unauthorized', { extensions: { code: 'UNAUTHENTICATED' } })
} }
return { userId: payload.sub, teamUuid, scopes: ['teams:member', 'manager'] } return { userId: payload.sub, teamUuid, scopes: ['teams:member', 'manager'] }