// Auteur : Simon-Pierre Boucher — contact@spboucher.ai // Départ du flux Sign in with Apple : pose state + next en témoins, // redirige vers l'écran de consentement Apple. // // ⚠️ Avec les scopes « name email », Apple impose response_mode=form_post : // le retour arrive en POST cross-site, donc les témoins d'état doivent être // SameSite=None; Secure (Lax ne serait pas renvoyé). Conséquence : le flux // exige HTTPS — Apple refuse de toute façon les redirect_uri en http. import { NextRequest, NextResponse } from "next/server"; import crypto from "crypto"; import { BASE_URL, safeNext } from "@/lib/auth"; export async function GET(req: NextRequest) { const clientId = process.env.APPLE_CLIENT_ID; if (!clientId) { return NextResponse.redirect( new URL("/connexion?error=apple-non-configure", BASE_URL), ); } const next = safeNext(req.nextUrl.searchParams.get("next")); const state = crypto.randomBytes(16).toString("hex"); const url = new URL("https://appleid.apple.com/auth/authorize"); url.searchParams.set("client_id", clientId); url.searchParams.set("redirect_uri", `${BASE_URL}/api/auth/callback/apple`); url.searchParams.set("response_type", "code"); url.searchParams.set("scope", "name email"); url.searchParams.set("response_mode", "form_post"); url.searchParams.set("state", state); const res = NextResponse.redirect(url); const opts = { httpOnly: true, secure: true, sameSite: "none" as const, path: "/", maxAge: 600, }; res.cookies.set("ka_apple_state", state, opts); res.cookies.set("ka_apple_next", next, opts); return res; }