57 lines
1.5 KiB
Go
57 lines
1.5 KiB
Go
package auth
|
|
|
|
import (
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
// CookieName is the single httpOnly cookie that carries the JWT.
|
|
const CookieName = "spsays_auth"
|
|
|
|
// CookieOptions captures the per-environment knobs for the auth cookie.
|
|
type CookieOptions struct {
|
|
Domain string // empty in dev; ".prabhupadasays.org" in prod for subdomain sharing
|
|
Secure bool // true in production (HTTPS-only)
|
|
}
|
|
|
|
// Set writes the JWT into a Secure, httpOnly, SameSite=Lax cookie.
|
|
// SameSite=Lax + same-registrable-domain (prabhupadasays.org / api.prabhupadasays.org)
|
|
// is enough for cross-subdomain auth without resorting to SameSite=None.
|
|
func Set(w http.ResponseWriter, token string, expires time.Time, opts CookieOptions) {
|
|
http.SetCookie(w, &http.Cookie{
|
|
Name: CookieName,
|
|
Value: token,
|
|
Path: "/",
|
|
Domain: opts.Domain,
|
|
Expires: expires,
|
|
MaxAge: int(time.Until(expires).Seconds()),
|
|
HttpOnly: true,
|
|
Secure: opts.Secure,
|
|
SameSite: http.SameSiteLaxMode,
|
|
})
|
|
}
|
|
|
|
// Clear overwrites the auth cookie with an immediately-expired one.
|
|
func Clear(w http.ResponseWriter, opts CookieOptions) {
|
|
http.SetCookie(w, &http.Cookie{
|
|
Name: CookieName,
|
|
Value: "",
|
|
Path: "/",
|
|
Domain: opts.Domain,
|
|
Expires: time.Unix(0, 0),
|
|
MaxAge: -1,
|
|
HttpOnly: true,
|
|
Secure: opts.Secure,
|
|
SameSite: http.SameSiteLaxMode,
|
|
})
|
|
}
|
|
|
|
// Read pulls the raw JWT out of the request cookie. Returns "" if missing.
|
|
func Read(r *http.Request) string {
|
|
c, err := r.Cookie(CookieName)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return c.Value
|
|
}
|