gongxiangp2/lib/dingtalk-profile-token.ts

65 lines
1.9 KiB
TypeScript

import { decode, encode } from 'next-auth/jwt'
import type { NextRequest } from 'next/server'
import { resolveSecureAuthCookieFromRequest } from '@/lib/auth-cookie'
const PROFILE_TOKEN_PURPOSE = 'dingtalk-profile-completion'
const PROFILE_TOKEN_MAX_AGE_SECONDS = 10 * 60
const PROFILE_COOKIE_PATH = '/api/dingtalk/complete-profile'
const PROFILE_COOKIE_NAME = 'dingtalk-profile-token'
const SECURE_PROFILE_COOKIE_NAME = '__Secure-dingtalk-profile-token'
function getSecret() {
const secret = process.env.NEXTAUTH_SECRET
if (!secret) {
throw new Error('登录会话未配置 NEXTAUTH_SECRET')
}
return secret
}
export function getDingtalkProfileCookiePath() {
return PROFILE_COOKIE_PATH
}
export function getDingtalkProfileCookieName(request: NextRequest) {
return resolveSecureAuthCookieFromRequest(request)
? SECURE_PROFILE_COOKIE_NAME
: PROFILE_COOKIE_NAME
}
export function getDingtalkProfileCookieCandidates(request: NextRequest) {
const preferred = getDingtalkProfileCookieName(request)
return preferred === SECURE_PROFILE_COOKIE_NAME
? [SECURE_PROFILE_COOKIE_NAME, PROFILE_COOKIE_NAME]
: [PROFILE_COOKIE_NAME, SECURE_PROFILE_COOKIE_NAME]
}
export async function createDingtalkProfileToken(userId: string) {
return encode({
secret: getSecret(),
maxAge: PROFILE_TOKEN_MAX_AGE_SECONDS,
token: {
sub: userId,
purpose: PROFILE_TOKEN_PURPOSE,
} as any,
})
}
export async function verifyDingtalkProfileToken(token: string | null | undefined) {
const normalizedToken = String(token || '').trim()
if (!normalizedToken) {
return null
}
try {
const payload = await decode({ token: normalizedToken, secret: getSecret() })
if (payload?.purpose !== PROFILE_TOKEN_PURPOSE || !payload.sub) {
return null
}
return String(payload.sub)
} catch {
return null
}
}
export const DINGTALK_PROFILE_TOKEN_MAX_AGE_SECONDS = PROFILE_TOKEN_MAX_AGE_SECONDS