package api import ( "context" "net/http" "time" "messenger/internal/auth" ) const ( accessCookieName = "messenger_access" refreshCookieName = "messenger_refresh" accessTTL = 15 * time.Minute refreshTTL = 30 * 24 * time.Hour ) type ctxKey string // ctxKeyUserID is the context key carrying the authenticated user ID. const ctxKeyUserID ctxKey = "messenger.userID" func userIDFrom(ctx context.Context) (int64, bool) { id, ok := ctx.Value(ctxKeyUserID).(int64) return id, ok } func withUserID(ctx context.Context, userID int64) context.Context { return context.WithValue(ctx, ctxKeyUserID, userID) } // requireAuth parses the access-token cookie and injects the user ID // into the request context. func requireAuth(tm *auth.TokenManager, next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { cookie, err := r.Cookie(accessCookieName) if err != nil { writeError(w, http.StatusUnauthorized, "missing access token") return } userID, err := tm.ParseAccessToken(cookie.Value) if err != nil { writeError(w, http.StatusUnauthorized, "invalid access token") return } next(w, r.WithContext(withUserID(r.Context(), userID))) } } func setAuthCookies(w http.ResponseWriter, accessToken, refreshToken string, secure bool) { http.SetCookie(w, &http.Cookie{ Name: accessCookieName, Value: accessToken, Path: "/", HttpOnly: true, Secure: secure, SameSite: http.SameSiteLaxMode, MaxAge: int(accessTTL.Seconds()), }) http.SetCookie(w, &http.Cookie{ Name: refreshCookieName, Value: refreshToken, Path: "/", HttpOnly: true, Secure: secure, SameSite: http.SameSiteLaxMode, MaxAge: int(refreshTTL.Seconds()), }) } func clearAuthCookies(w http.ResponseWriter) { http.SetCookie(w, &http.Cookie{Name: accessCookieName, Path: "/", MaxAge: -1}) http.SetCookie(w, &http.Cookie{Name: refreshCookieName, Path: "/", MaxAge: -1}) }