First steps towards the SAS partnership * otp flow now pretends to do the linking * Update LinkAccountForm header * Update redirect times * Clean up comments * Set maxAge on sas cookies * make all SAS routes protected * Merge remote-tracking branch 'refs/remotes/origin/feature/sas-login' into feature/sas-login * Require auth for sas link flow * Fix resend otp * Add error support to OneTimePasswordForm * Add Sentry to SAS error boundary * Move SAS_REQUEST_OTP_STATE_STORAGE_COOKIE_NAME * Add missing translations * Merge branch 'master' of bitbucket.org:scandic-swap/web into feature/sas-login * Merge branch 'feature/sas-login' of bitbucket.org:scandic-swap/web into feature/sas-login * Add TooManyCodesError component * Refactor GenericError to support new errors * Add FailedAttemptsError * remove removed component <VWOScript/> * Merge branch 'feature/sas-login' of bitbucket.org:scandic-swap/web into feature/sas-login * remove local cookie-bot reference * Fix sas campaign logo scaling * feature toggle the SAS stuff * Merge branch 'feature/sas-login' of bitbucket.org:scandic-swap/web into feature/sas-login * fix: use env vars for SAS endpoints Approved-by: Linus Flood
106 lines
2.8 KiB
TypeScript
106 lines
2.8 KiB
TypeScript
import { cookies } from "next/headers"
|
|
import { redirect } from "next/navigation"
|
|
import { z } from "zod"
|
|
|
|
import { env } from "@/env/server"
|
|
import { serverClient } from "@/lib/trpc/server"
|
|
|
|
import { safeTry } from "@/utils/safeTry"
|
|
|
|
import { SAS_TOKEN_STORAGE_KEY, stateSchema } from "../sasUtils"
|
|
|
|
import type { NextRequest } from "next/server"
|
|
|
|
const searchParamsSchema = z.object({
|
|
code: z.string(),
|
|
state: z.string(),
|
|
})
|
|
const tokenResponseSchema = z.object({
|
|
access_token: z.string(),
|
|
expires_in: z.number(),
|
|
token_type: z.literal("Bearer"),
|
|
})
|
|
|
|
export async function GET(
|
|
request: NextRequest,
|
|
{ params }: { params: { lang: string } }
|
|
) {
|
|
const { lang } = params
|
|
|
|
const result = searchParamsSchema.safeParse({
|
|
code: request.nextUrl.searchParams.get("code"),
|
|
state: request.nextUrl.searchParams.get("state"),
|
|
})
|
|
|
|
if (!result.success) {
|
|
console.error("[SAS] Invalid search params", result.error)
|
|
redirect(`/${lang}/sas-x-scandic/error?errorCode=invalid_query`)
|
|
}
|
|
const { code, state } = result.data
|
|
|
|
const tokenResponse = await fetch(
|
|
new URL("oauth/token", env.SAS_AUTH_ENDPOINT),
|
|
{
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
},
|
|
body: new URLSearchParams({
|
|
grant_type: "authorization_code",
|
|
code: code,
|
|
redirect_uri: new URL(
|
|
`/${lang}/sas-x-scandic/callback`,
|
|
new URL(env.PUBLIC_URL)
|
|
).toString(),
|
|
client_id: env.SAS_AUTH_CLIENTID,
|
|
}),
|
|
}
|
|
)
|
|
|
|
if (!tokenResponse.ok) {
|
|
const error = await tokenResponse.text()
|
|
console.error("[SAS] Failed to get token", error)
|
|
redirect(`/${lang}/sas-x-scandic/error?errorCode=token_error`)
|
|
}
|
|
|
|
const tokenData = tokenResponseSchema.parse(await tokenResponse.json())
|
|
|
|
const stateResult = stateSchema.safeParse(
|
|
JSON.parse(decodeURIComponent(state))
|
|
)
|
|
if (!stateResult.success) {
|
|
redirect(`/${lang}/sas-x-scandic/error?errorCode=invalid_state`)
|
|
}
|
|
|
|
const cookieStore = cookies()
|
|
cookieStore.set(SAS_TOKEN_STORAGE_KEY, tokenData.access_token, {
|
|
maxAge: 3600,
|
|
httpOnly: true,
|
|
})
|
|
|
|
if (stateResult.data.intent === "link") {
|
|
const [data, error] = await safeTry(
|
|
serverClient().partner.sas.requestOtp({})
|
|
)
|
|
// status: 'SENT' => OK
|
|
if (!data || error) {
|
|
//TODO: Check what error we get
|
|
console.error("[SAS] Failed to request OTP", error)
|
|
redirect(`/${lang}/sas-x-scandic/error`)
|
|
}
|
|
|
|
console.log("[SAS] Request OTP response", data)
|
|
|
|
const otpUrl = new URL(
|
|
`/${lang}/sas-x-scandic/otp`,
|
|
new URL(env.PUBLIC_URL)
|
|
)
|
|
otpUrl.searchParams.set("intent", stateResult.data.intent)
|
|
otpUrl.searchParams.set("to", data.otpReceiver)
|
|
|
|
redirect(otpUrl.toString())
|
|
}
|
|
|
|
redirect(`/${lang}/sas-x-scandic/error?errorCode=unknown_intent`)
|
|
}
|