refactor(auth): rename paymentBridge → signupBridge
After commit 90acc35 issued the cookie for $0 signups too, the "payment"
framing was wrong — there's no payment in a $0 signup. The cookie is
about bridging the gap between signup-form submit and email verify, not
about payment specifically.
Changes:
- setPaymentBridgeCookie → setSignupBridgeCookie
- getPaymentBridgeMember → getSignupBridgeMember
- Cookie wire name payment-bridge → signup-bridge
- JWT scope payment_bridge → signup_bridge
Touches both /api/helcim/subscription (signup activation) and
/api/helcim/initialize-payment (paid Helcim checkout) which both consume
the cookie. In-flight signup sessions started before this lands will
need to re-submit the form (cookie name mismatch); cutover hasn't
happened yet, so the only impact is local dev sessions.
This commit is contained in:
parent
c6a5e25d06
commit
9b79ae6bf4
8 changed files with 36 additions and 35 deletions
|
|
@ -4,7 +4,7 @@ import { connectDB } from '../../utils/mongoose.js'
|
|||
import { createHelcimCustomer } from '../../utils/helcim.js'
|
||||
import PreRegistration from '../../models/preRegistration.js'
|
||||
import { sendMagicLink } from '../../utils/magicLink.js'
|
||||
import { setPaymentBridgeCookie } from '../../utils/auth.js'
|
||||
import { setSignupBridgeCookie } from '../../utils/auth.js'
|
||||
import { rateLimit } from '../../utils/rateLimit.js'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
|
|
@ -116,10 +116,10 @@ export default defineEventHandler(async (event) => {
|
|||
})
|
||||
|
||||
// Signup completes (paid checkout or free activation) before the magic
|
||||
// link is clicked, so issue a short-lived, payment-only bridge cookie
|
||||
// that lets /api/helcim/initialize-payment and /api/helcim/subscription
|
||||
// identify the member without a verified auth session.
|
||||
setPaymentBridgeCookie(event, member)
|
||||
// link is clicked, so issue a short-lived signup-bridge cookie that lets
|
||||
// /api/helcim/initialize-payment and /api/helcim/subscription identify
|
||||
// the member without a verified auth session.
|
||||
setSignupBridgeCookie(event, member)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import Member from '../../models/member.js'
|
|||
import { loadPublicEvent } from '../../utils/loadEvent.js'
|
||||
import { loadPublicSeries } from '../../utils/loadSeries.js'
|
||||
import { calculateTicketPrice, calculateSeriesTicketPrice, hasMemberAccess } from '../../utils/tickets.js'
|
||||
import { requireAuth, getOptionalMember, getPaymentBridgeMember } from '../../utils/auth.js'
|
||||
import { requireAuth, getOptionalMember, getSignupBridgeMember } from '../../utils/auth.js'
|
||||
import { initializeHelcimPaySession } from '../../utils/helcim.js'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
|
|
@ -17,7 +17,7 @@ export default defineEventHandler(async (event) => {
|
|||
|
||||
if (!isTicket) {
|
||||
if (isMembershipSignup) {
|
||||
const bridgeMember = await getPaymentBridgeMember(event)
|
||||
const bridgeMember = await getSignupBridgeMember(event)
|
||||
if (!bridgeMember) {
|
||||
await requireAuth(event)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { getHelcimPlanId, requiresPayment } from '../../config/contributions.js'
|
|||
import Member from '../../models/member.js'
|
||||
import { connectDB } from '../../utils/mongoose.js'
|
||||
import { getSlackService } from '../../utils/slack.ts'
|
||||
import { requireAuth, getPaymentBridgeMember } from '../../utils/auth.js'
|
||||
import { requireAuth, getSignupBridgeMember } from '../../utils/auth.js'
|
||||
import { createHelcimSubscription, generateIdempotencyKey, listHelcimCustomerTransactions } from '../../utils/helcim.js'
|
||||
import { sendWelcomeEmail } from '../../utils/resend.js'
|
||||
import { upsertPaymentFromHelcim } from '../../utils/payments.js'
|
||||
|
|
@ -11,8 +11,8 @@ import { upsertPaymentFromHelcim } from '../../utils/payments.js'
|
|||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
// Membership signup completes subscription before email verify; allow the
|
||||
// payment-bridge cookie set by /api/helcim/customer to satisfy auth here.
|
||||
const bridgeMember = await getPaymentBridgeMember(event)
|
||||
// signup-bridge cookie set by /api/helcim/customer to satisfy auth here.
|
||||
const bridgeMember = await getSignupBridgeMember(event)
|
||||
if (!bridgeMember) {
|
||||
await requireAuth(event)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,26 +23,27 @@ export function setAuthCookie(event, member) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Issue a 30-minute payment-bridge cookie scoped to membership-signup checkout.
|
||||
* Issue a 30-minute signup-bridge cookie scoped to membership-signup flow.
|
||||
*
|
||||
* The signup flow (POST /api/helcim/customer) defers the full session cookie
|
||||
* to email-verify (magic link). For paid tiers the user still needs to complete
|
||||
* Helcim checkout in the same browser tab — this short-lived, payment-only
|
||||
* token lets `/api/helcim/initialize-payment` accept the call without a full
|
||||
* session. The cookie is NOT honored by requireAuth and grants nothing else.
|
||||
* to email-verify (magic link). The bridge cookie lets the in-progress signup
|
||||
* complete its activation step (free or paid) before that magic link is
|
||||
* clicked: /api/helcim/subscription accepts it for $0 activation, and
|
||||
* /api/helcim/initialize-payment accepts it for paid Helcim checkout.
|
||||
* The cookie is NOT honored by requireAuth and grants nothing else.
|
||||
*/
|
||||
export function setPaymentBridgeCookie(event, member) {
|
||||
export function setSignupBridgeCookie(event, member) {
|
||||
const token = jwt.sign(
|
||||
{
|
||||
memberId: member._id.toString(),
|
||||
email: member.email,
|
||||
scope: 'payment_bridge'
|
||||
scope: 'signup_bridge'
|
||||
},
|
||||
useRuntimeConfig(event).jwtSecret,
|
||||
{ expiresIn: '30m' }
|
||||
)
|
||||
|
||||
setCookie(event, 'payment-bridge', token, {
|
||||
setCookie(event, 'signup-bridge', token, {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
sameSite: 'lax',
|
||||
|
|
@ -52,12 +53,12 @@ export function setPaymentBridgeCookie(event, member) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Verify a payment-bridge cookie and return the associated Member, or null.
|
||||
* Used by /api/helcim/initialize-payment to allow the membership-signup
|
||||
* checkout to proceed before email verification.
|
||||
* Verify a signup-bridge cookie and return the associated Member, or null.
|
||||
* Used by /api/helcim/subscription and /api/helcim/initialize-payment to
|
||||
* let the in-progress signup complete activation before email verification.
|
||||
*/
|
||||
export async function getPaymentBridgeMember(event) {
|
||||
const token = getCookie(event, 'payment-bridge')
|
||||
export async function getSignupBridgeMember(event) {
|
||||
const token = getCookie(event, 'signup-bridge')
|
||||
if (!token) return null
|
||||
|
||||
let decoded
|
||||
|
|
@ -67,7 +68,7 @@ export async function getPaymentBridgeMember(event) {
|
|||
return null
|
||||
}
|
||||
|
||||
if (decoded.scope !== 'payment_bridge') return null
|
||||
if (decoded.scope !== 'signup_bridge') return null
|
||||
|
||||
await connectDB()
|
||||
const member = await Member.findById(decoded.memberId)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue