Migrate KYC backend from Django to Express + Apollo Server + Prisma
All checks were successful
Build Docker Image / build (push) Successful in 2m12s

Replace Python/Django/Graphene with TypeScript/Express/Apollo Server.
Same 3 endpoints (public/user/m2m), same JWT auth via Logto.
Prisma replaces Django ORM. MongoDB, Temporal and SurrealDB integrations preserved.
This commit is contained in:
Ruslan Bakiev
2026-03-09 09:16:44 +07:00
parent 59dcff3d64
commit bce6b47896
45 changed files with 5079 additions and 2936 deletions

47
src/auth.ts Normal file
View File

@@ -0,0 +1,47 @@
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<AuthContext> {
// 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<AuthContext> {
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<AuthContext> {
return { scopes: [], isM2M: true }
}