feat(15-01): extend createSigningToken with signerEmail, add signer-download token pair
- createSigningToken now accepts optional signerEmail param and persists to DB - Added createSignerDownloadToken (72h TTL, purpose: signer-download) - Added verifySignerDownloadToken with purpose claim validation
This commit is contained in:
@@ -4,7 +4,7 @@ import { signingTokens } from '@/lib/db/schema';
|
||||
|
||||
const getSecret = () => new TextEncoder().encode(process.env.SIGNING_JWT_SECRET!);
|
||||
|
||||
export async function createSigningToken(documentId: string): Promise<{ token: string; jti: string; expiresAt: Date }> {
|
||||
export async function createSigningToken(documentId: string, signerEmail?: string): Promise<{ token: string; jti: string; expiresAt: Date }> {
|
||||
const jti = crypto.randomUUID();
|
||||
const expiresAt = new Date(Date.now() + 72 * 60 * 60 * 1000); // 72 hours
|
||||
|
||||
@@ -19,6 +19,7 @@ export async function createSigningToken(documentId: string): Promise<{ token: s
|
||||
await db.insert(signingTokens).values({
|
||||
jti,
|
||||
documentId,
|
||||
signerEmail: signerEmail ?? null,
|
||||
expiresAt,
|
||||
});
|
||||
|
||||
@@ -62,3 +63,19 @@ export async function verifyAgentDownloadToken(token: string): Promise<{ documen
|
||||
if (payload['purpose'] !== 'agent-download') throw new Error('Not an agent download token');
|
||||
return { documentId: payload['documentId'] as string };
|
||||
}
|
||||
|
||||
// Signer download token — purpose: 'signer-download', 72h TTL, no DB record
|
||||
// Sent to signers on completion so they can download the fully signed PDF.
|
||||
export async function createSignerDownloadToken(documentId: string): Promise<string> {
|
||||
return await new SignJWT({ documentId, purpose: 'signer-download' })
|
||||
.setProtectedHeader({ alg: 'HS256' })
|
||||
.setIssuedAt()
|
||||
.setExpirationTime('72h')
|
||||
.sign(getSecret());
|
||||
}
|
||||
|
||||
export async function verifySignerDownloadToken(token: string): Promise<{ documentId: string }> {
|
||||
const { payload } = await jwtVerify(token, getSecret());
|
||||
if (payload['purpose'] !== 'signer-download') throw new Error('Not a signer download token');
|
||||
return { documentId: payload['documentId'] as string };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user