--- name: http_session_cookie_middleware kind: function lang: go domain: infra version: "1.0.0" purity: impure signature: "func HTTPSessionCookieMiddleware(cfg SessionCookieConfig) Middleware" description: "Middleware HTTP que valida sesiones via cookie o header Authorization: Bearer. Inyecta el userID en el contexto si la sesion es valida. Delega sin validar los paths en SkipPaths." params: - name: cfg desc: "Configuracion: DB con tabla sessions, nombre de cookie, prefijos a saltarse y clave tipada para el contexto." output: "Middleware (func(http.Handler) http.Handler) que protege los endpoints no listados en SkipPaths." tags: [http, auth, session, cookie, middleware, bearer] uses_functions: - session_validate_go_infra - http_error_response_go_infra uses_types: - Session_go_infra returns: [] returns_optional: false error_type: "error_go_core" imports: - context - database/sql - net/http - strings tested: true tests: - "sesion valida via cookie deja pasar y expone userID en contexto" - "sin cookie ni header devuelve 401" - "skip path bypassa sin validar token" test_file_path: "functions/infra/http_session_cookie_middleware_test.go" file_path: "functions/infra/http_session_cookie_middleware.go" --- ## Ejemplo ```go type ctxKey string const userKey ctxKey = "user_id" mw := infra.HTTPSessionCookieMiddleware(infra.SessionCookieConfig{ DB: db, CookieName: "kanban_session", SkipPaths: []string{"/api/auth/", "/health"}, UserCtxKey: userKey, }) mux := http.NewServeMux() mux.Handle("/api/", mw(apiRouter)) // En un handler: userID, ok := infra.UserIDFromContext(r.Context(), userKey) ``` ## Notas `SessionCookieConfig.UserCtxKey` debe ser una clave tipada propia del caller (no `string`) para evitar colisiones en el contexto. Patron canonico: `type ctxKey string; const userKey ctxKey = "user_id"`. El helper `UserIDFromContext(ctx, key)` esta en el mismo paquete y hace el type-assert de forma segura retornando `("", false)` si no hay valor o el tipo no coincide. El orden de extraccion del token es: cookie → `Authorization: Bearer`. Si ninguno esta presente responde 401 con `{"code":"unauthorized","message":"session required"}`.