@cipherstash/nextjs
Version:
Nextjs package for use with @cipherstash/protect
116 lines (95 loc) • 3.12 kB
text/typescript
import { NextResponse } from 'next/server'
import { logger } from '../../../utils/logger'
import {
CS_COOKIE_NAME,
type CtsToken,
type GetCtsTokenResponse,
} from '../index'
/**
* Extracts the workspace ID from a CRN string.
* CRN format: crn:region.aws:ID
*
* @param crn The CRN string to extract from
* @returns The workspace ID portion of the CRN
*/
function extractWorkspaceIdFromCrn(crn: string): string {
const match = crn.match(/crn:[^:]+:([^:]+)$/)
if (!match) {
throw new Error('Invalid CRN format')
}
return match[1]
}
export function loadWorkSpaceId(suppliedCrn?: string): string {
if (suppliedCrn) {
return extractWorkspaceIdFromCrn(suppliedCrn)
}
if (!process.env.CS_WORKSPACE_CRN) {
throw new Error(
'You have not defined a workspace CRN in your config file, or the CS_WORKSPACE_CRN environment variable.',
)
}
return extractWorkspaceIdFromCrn(process.env.CS_WORKSPACE_CRN)
}
// Can be used independently of the Next.js middleware
export const fetchCtsToken = async (oidcToken: string): GetCtsTokenResponse => {
const workspaceId = loadWorkSpaceId()
if (!workspaceId) {
logger.error(
'The "CS_WORKSPACE_ID" environment variable is not set, and is required by protectClerkMiddleware. No CipherStash session will be set.',
)
return {
success: false,
error: 'The "CS_WORKSPACE_ID" environment variable is not set.',
}
}
const ctsEndoint =
process.env.CS_CTS_ENDPOINT ||
'https://ap-southeast-2.aws.auth.viturhosted.net'
const ctsResponse = await fetch(`${ctsEndoint}/api/authorize`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
workspaceId,
oidcToken,
}),
})
if (!ctsResponse.ok) {
logger.debug(`Failed to fetch CTS token: ${ctsResponse.statusText}`)
logger.error(
'There was an issue communicating with the CipherStash CTS API, the CipherStash session was not set. If the issue persists, please contact support.',
)
return {
success: false,
error: `Failed to fetch CTS token: ${ctsResponse.statusText}`,
}
}
const cts_token = (await ctsResponse.json()) as CtsToken
return {
success: true,
ctsToken: cts_token,
}
}
// Used in the Next.js middleware
export const setCtsToken = async (oidcToken: string, res?: NextResponse) => {
const ctsResponse = await fetchCtsToken(oidcToken)
const cts_token = ctsResponse.ctsToken
if (!cts_token) {
logger.debug(`Failed to fetch CTS token: ${ctsResponse.error}`)
logger.error(
'There was an issue fetching the CipherStash session, the CipherStash session was not set. If the issue persists, please contact support.',
)
return res ?? NextResponse.next()
}
// Setting cookies on the request and response using the `ResponseCookies` API
const response = res ?? NextResponse.next()
response.cookies.set({
name: CS_COOKIE_NAME,
value: JSON.stringify(cts_token),
expires: new Date(cts_token.expiry * 1000),
sameSite: 'lax',
path: '/',
})
return response
}