Tratar o resultado
O navegador do cliente o traz de volta, então nada em texto puro nessa URL é confiável. Por isso o broker adiciona um token assinado.
O retorno
return_to
https://yourapp.com/billing/callback?session_id=7f3a9c1e-…&pay_token=eyJhbGciOiJIUzI1NiJ9…
pay_token é um JWS (HS256) assinado com a sua secret key. Verifique no seu backend, nunca no navegador. Não se chama token para que bibliotecas de autenticação que leem um token da URL (Clowk, Devise e afins) não o confundam:
Ruby
claims = JWT.decode(params[:pay_token], ENV["PAY_SECRET_KEY"], true, algorithm: "HS256", iss: "pay", verify_iss: true, sub: params[:session_id], verify_sub: true).first claims["status"] # "paid", "failed", "expired", … claims["amount"] # "49.9", with "currency", "method" and "customer"
Node
import jwt from "jsonwebtoken" const claims = jwt.verify(req.query.pay_token, process.env.PAY_SECRET_KEY, { algorithms: ["HS256"], issuer: "pay", subject: req.query.session_id, })
Regras
- 1Fixe HS256 e recuse qualquer outro algoritmo, inclusive none.
- 2O token expira 15 minutos depois do redirect e pode ser reutilizado até lá: libere o que foi comprado uma vez por session_id.
- 3Ele prova o status no momento do redirect. Reembolsos e pagamentos atrasados chegam por webhook (session.paid, session.refunded).
- 4Prefere não verificar tokens? Ignore o token e chame GET /api/v1/sessions/:session_id com a sua key.