{"info":{"_postman_id":"9a69f4d5-3802-4771-95dd-94356ce69f9a","name":"Session-Management","description":"<html><head></head><body><h1 id=\"nestjs-session-management-setup-testing-guide\">NestJS Session Management - Setup &amp; Testing Guide</h1>\n<h2 id=\"quick-setup\">Quick Setup:</h2>\n<h3 id=\"prerequisites\">Prerequisites</h3>\n<ul>\n<li><p>Node.js (v18+)</p>\n</li>\n<li><p>PostgreSQL (v14+)</p>\n</li>\n<li><p>Redis (v7+)</p>\n</li>\n<li><p>Postman (for testing)</p>\n</li>\n<li><p>Docker</p>\n</li>\n</ul>\n</body></html>","schema":"https://schema.getpostman.com/json/collection/v2.0.0/collection.json","toc":[{"content":"NestJS Session Management - Setup & Testing Guide","slug":"nestjs-session-management-setup-testing-guide"}],"owner":"40852797","collectionId":"9a69f4d5-3802-4771-95dd-94356ce69f9a","publishedId":"2sBXVo7n1J","public":true,"customColor":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"FF6C37"},"publishDate":"2026-01-28T23:54:30.000Z"},"item":[{"name":"Jwt","item":[{"name":"register","id":"faeb330a-9c63-44f4-a074-46d1a273ce44","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\r\n  \"email\": \"user@example.com\",\r\n  \"password\": \"password123\",\r\n  \"name\": \"JWT User\"\r\n}","options":{"raw":{"language":"json"}}},"url":"http://localhost:3000/auth/jwt/register","urlObject":{"protocol":"http","port":"3000","path":["auth","jwt","register"],"host":["localhost"],"query":[],"variable":[]}},"response":[{"id":"d29fffc1-8925-411d-b0c0-e03100929b32","name":"New Request","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\r\n  \"email\": \"user@example.com\",\r\n  \"password\": \"password123\",\r\n  \"name\": \"JWT User\"\r\n}","options":{"raw":{"language":"json"}}},"url":"http://localhost:3000/auth/jwt/register"},"status":"Created","code":201,"_postman_previewlanguage":"Text","header":[{"key":"X-Powered-By","value":"Express"},{"key":"Vary","value":"Origin"},{"key":"Access-Control-Allow-Credentials","value":"true"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"168"},{"key":"ETag","value":"W/\"a8-mDze97tyibLbjhsTgPuuX6+KSyc\""},{"key":"Date","value":"Wed, 28 Jan 2026 23:12:53 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"id\": \"34fc5a71-a70a-407d-8b56-02158f8f3e78\",\n    \"email\": \"user@example.com\",\n    \"name\": \"JWT User\",\n    \"createdAt\": \"2026-01-28T22:12:56.311Z\",\n    \"updatedAt\": \"2026-01-28T22:12:56.311Z\"\n}"}],"_postman_id":"faeb330a-9c63-44f4-a074-46d1a273ce44"},{"name":"login","id":"6b41e560-ec38-4f70-9561-4d93b6eb02e6","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\r\n  \"email\": \"user@example.com\",\r\n  \"password\": \"password123\"\r\n}","options":{"raw":{"language":"json"}}},"url":"http://localhost:3000/auth/jwt/login","description":"<p>Copy the <code>access_token</code> and save it as a Postman variable</p>\n","urlObject":{"protocol":"http","port":"3000","path":["auth","jwt","login"],"host":["localhost"],"query":[],"variable":[]}},"response":[{"id":"a42b891e-0025-4054-a0bb-c6c29affcf7a","name":"login","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\r\n  \"email\": \"user@example.com\",\r\n  \"password\": \"password123\"\r\n}","options":{"raw":{"language":"json"}}},"url":"http://localhost:3000/auth/jwt/login"},"status":"Created","code":201,"_postman_previewlanguage":"Text","header":[{"key":"X-Powered-By","value":"Express"},{"key":"Vary","value":"Origin"},{"key":"Access-Control-Allow-Credentials","value":"true"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"443"},{"key":"ETag","value":"W/\"1bb-9tw1/mXfWhiWJEfJTf6p6dR2QN0\""},{"key":"Date","value":"Wed, 28 Jan 2026 23:15:15 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"access_token\": \"{{vault:json-web-token}}\",\n    \"user\": {\n        \"id\": \"34fc5a71-a70a-407d-8b56-02158f8f3e78\",\n        \"email\": \"user@example.com\",\n        \"name\": \"JWT User\",\n        \"createdAt\": \"2026-01-28T22:12:56.311Z\",\n        \"updatedAt\": \"2026-01-28T22:12:56.311Z\"\n    }\n}"}],"_postman_id":"6b41e560-ec38-4f70-9561-4d93b6eb02e6"},{"name":"profile","id":"3719496d-714f-4fac-a7f9-6360f7b1542f","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"url":"","description":"<ul>\n<li>Go to Authorization tab</li>\n<li>Select \"Bearer Token\"</li>\n<li>Paste the token from login response</li>\n</ul>\n","urlObject":{"query":[],"variable":[]}},"response":[{"id":"80a12a84-9fa0-4542-b130-47d972d13795","name":"bad-request","originalRequest":{"method":"GET","header":[],"url":"http://localhost:3000/auth/jwt/profile"},"status":"Unauthorized","code":401,"_postman_previewlanguage":"Text","header":[{"key":"X-Powered-By","value":"Express"},{"key":"Vary","value":"Origin"},{"key":"Access-Control-Allow-Credentials","value":"true"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"43"},{"key":"ETag","value":"W/\"2b-dGnJzt6gv1nJjX6DJ9RztDWptng\""},{"key":"Date","value":"Wed, 28 Jan 2026 23:18:00 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Unauthorized\",\n    \"statusCode\": 401\n}"},{"id":"e06c2ff7-d725-4c72-aa4b-a2e1a8830b98","name":"profile","originalRequest":{"method":"GET","header":[],"url":"http://localhost:3000/auth/jwt/profile"},"status":"OK","code":200,"_postman_previewlanguage":"Text","header":[{"key":"X-Powered-By","value":"Express"},{"key":"Vary","value":"Origin"},{"key":"Access-Control-Allow-Credentials","value":"true"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"162"},{"key":"ETag","value":"W/\"a2-ipoEBMcwSCtWEZnHf1PH2zcSchU\""},{"key":"Date","value":"Wed, 28 Jan 2026 23:19:05 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"JWT authentication successful\",\n    \"user\": {\n        \"userId\": \"34fc5a71-a70a-407d-8b56-02158f8f3e78\",\n        \"email\": \"user@example.com\",\n        \"name\": \"JWT User\"\n    },\n    \"strategy\": \"jwt\"\n}"}],"_postman_id":"3719496d-714f-4fac-a7f9-6360f7b1542f"},{"name":"logout","id":"06bb5f68-f63a-41a2-ba47-3f767255cdb8","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"url":"","urlObject":{"query":[],"variable":[]}},"response":[{"id":"633d03ea-9831-4df1-8b18-cb44a29bdae7","name":"logout","originalRequest":{"method":"POST","header":[],"url":"http://localhost:3000/auth/jwt/logout"},"status":"Created","code":201,"_postman_previewlanguage":"Text","header":[{"key":"X-Powered-By","value":"Express"},{"key":"Vary","value":"Origin"},{"key":"Access-Control-Allow-Credentials","value":"true"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"61"},{"key":"ETag","value":"W/\"3d-f/xXxb7GkwDLMmMJ9VTUrh9jxxU\""},{"key":"Date","value":"Wed, 28 Jan 2026 23:19:47 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"JWT logout successful, remove token from client\"\n}"}],"_postman_id":"06bb5f68-f63a-41a2-ba47-3f767255cdb8"}],"id":"567faf05-8592-423b-a930-2aec3a64a86c","description":"<p>Stateless authentication: the token itself carries all necessary user information. The server verifies the token's signature without maintaining a session.</p>\n<p><strong>Flow:</strong></p>\n<p>1. User logs in with credentials</p>\n<p>2. Server generates a JWT with user payload</p>\n<p>3. Client stores token (e.g., localStorage)</p>\n<p>4. Client sends token in the <code>Authorization</code> header on each request</p>\n<p>5. Server verifies the token’s signature</p>\n<p><strong>Pros</strong></p>\n<ul>\n<li><p>Scalable (no server session state)</p>\n</li>\n<li><p>Works across domains</p>\n</li>\n</ul>\n<p><strong>Cons</strong></p>\n<ul>\n<li><p>Cannot easily invalidate tokens</p>\n</li>\n<li><p>Token size can be large</p>\n</li>\n<li><p>Compromised tokens can allow unauthorized</p>\n</li>\n</ul>\n","_postman_id":"567faf05-8592-423b-a930-2aec3a64a86c"},{"name":"Server-session","item":[{"name":"register","id":"6df5e5f4-3fca-40c9-a936-ce5f77d361fa","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\r\n  \"email\": \"2user@example.com\",\r\n  \"password\": \"password123\",\r\n  \"name\": \"Session User\"\r\n}","options":{"raw":{"language":"json"}}},"url":"http://localhost:3000/auth/session/register","urlObject":{"protocol":"http","port":"3000","path":["auth","session","register"],"host":["localhost"],"query":[],"variable":[]}},"response":[{"id":"e30b9c58-2b47-4ed1-8bd4-69cf22edfd68","name":"register","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\r\n  \"email\": \"2user@example.com\",\r\n  \"password\": \"password123\",\r\n  \"name\": \"Session User\"\r\n}","options":{"raw":{"language":"json"}}},"url":"http://localhost:3000/auth/session/register"},"status":"Created","code":201,"_postman_previewlanguage":"Text","header":[{"key":"X-Powered-By","value":"Express"},{"key":"Vary","value":"Origin"},{"key":"Access-Control-Allow-Credentials","value":"true"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"173"},{"key":"ETag","value":"W/\"ad-eWC4sjnqAC5s7hwILuQ3dxr+HyY\""},{"key":"Date","value":"Wed, 28 Jan 2026 23:21:13 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"id\": \"8ef0efdb-f2ca-460d-bb4d-b19efe514ecc\",\n    \"email\": \"2user@example.com\",\n    \"name\": \"Session User\",\n    \"createdAt\": \"2026-01-28T22:21:15.516Z\",\n    \"updatedAt\": \"2026-01-28T22:21:15.516Z\"\n}"}],"_postman_id":"6df5e5f4-3fca-40c9-a936-ce5f77d361fa"},{"name":"login","id":"0c6794fc-7f1b-494b-aa65-853b0eec09bd","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\r\n  \"email\": \"2user@example.com\",\r\n  \"password\": \"password123\"\r\n}","options":{"raw":{"language":"json"}}},"url":"http://localhost:3000/auth/session/login","description":"<p>Postman will automatically handle cookies. The session cookie will be stored</p>\n","urlObject":{"protocol":"http","port":"3000","path":["auth","session","login"],"host":["localhost"],"query":[],"variable":[]}},"response":[{"id":"814df90c-4ff5-4329-b18e-5d3ab49320a3","name":"login","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\r\n  \"email\": \"2user@example.com\",\r\n  \"password\": \"password123\"\r\n}","options":{"raw":{"language":"json"}}},"url":"http://localhost:3000/auth/session/login"},"status":"Created","code":201,"_postman_previewlanguage":"Text","header":[{"key":"X-Powered-By","value":"Express"},{"key":"Vary","value":"Origin"},{"key":"Access-Control-Allow-Credentials","value":"true"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"219"},{"key":"ETag","value":"W/\"db-RNsqVnTGlEjjjt12sZn31VNB4T4\""},{"key":"Set-Cookie","value":"connect.sid=s%3AyFU4LZMua1RbuEvmVfpUjVq9r92kEmbu.N2%2FNSVyHVfjvjoO%2FOx8tWJUMlbJCarMOvepBk8bcIAI; Path=/; Expires=Thu, 29 Jan 2026 23:22:29 GMT; HttpOnly; SameSite=Lax"},{"key":"Date","value":"Wed, 28 Jan 2026 23:22:29 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Session login successful\",\n    \"user\": {\n        \"id\": \"8ef0efdb-f2ca-460d-bb4d-b19efe514ecc\",\n        \"email\": \"2user@example.com\",\n        \"name\": \"Session User\",\n        \"createdAt\": \"2026-01-28T22:21:15.516Z\",\n        \"updatedAt\": \"2026-01-28T22:21:15.516Z\"\n    }\n}"}],"_postman_id":"0c6794fc-7f1b-494b-aa65-853b0eec09bd"},{"name":"profile","id":"426f7f8d-33b7-4301-8134-a6bc2ff56a23","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"url":"http://localhost:3000/auth/session/profile","description":"<p><strong>Note:</strong> No Authorization header needed! Cookie is sent automatically.</p>\n","urlObject":{"protocol":"http","port":"3000","path":["auth","session","profile"],"host":["localhost"],"query":[],"variable":[]}},"response":[{"id":"25776959-fa9d-4872-b71e-68254bc0c46d","name":"profile","originalRequest":{"method":"GET","header":[],"url":"http://localhost:3000/auth/session/profile"},"status":"OK","code":200,"_postman_previewlanguage":"Text","header":[{"key":"X-Powered-By","value":"Express"},{"key":"Vary","value":"Origin"},{"key":"Access-Control-Allow-Credentials","value":"true"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"149"},{"key":"ETag","value":"W/\"95-Cz36Eg4MQJuugaIKuu95dyjPAyI\""},{"key":"Date","value":"Wed, 28 Jan 2026 23:33:44 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Session authentication successful\",\n    \"user\": {\n        \"id\": \"8ef0efdb-f2ca-460d-bb4d-b19efe514ecc\",\n        \"email\": \"2user@example.com\"\n    },\n    \"strategy\": \"session\"\n}"}],"_postman_id":"426f7f8d-33b7-4301-8134-a6bc2ff56a23"},{"name":"logout","id":"f9b92973-b2ca-4580-af69-437eef6afd85","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"url":"http://localhost:3000/auth/session/logout","urlObject":{"protocol":"http","port":"3000","path":["auth","session","logout"],"host":["localhost"],"query":[],"variable":[]}},"response":[{"id":"78a214c6-2cab-45d9-ae84-f045773e99bc","name":"logout","originalRequest":{"method":"POST","header":[],"url":"http://localhost:3000/auth/session/logout"},"status":"Created","code":201,"_postman_previewlanguage":"Text","header":[{"key":"X-Powered-By","value":"Express"},{"key":"Vary","value":"Origin"},{"key":"Access-Control-Allow-Credentials","value":"true"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"39"},{"key":"ETag","value":"W/\"27-oDQKK7RL1khiBoVX82BPWT4RdLg\""},{"key":"Date","value":"Wed, 28 Jan 2026 23:34:35 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Session logout successful\"\n}"}],"_postman_id":"f9b92973-b2ca-4580-af69-437eef6afd85"}],"id":"e7deceb4-c941-433b-966c-76a1e1dabd02","description":"<p>A session ID is stored in a secure HTTP-only cookie, while session data is kept on the server (Redis). Each request validates the session via Redis.</p>\n<p><strong>Flow:</strong></p>\n<ol>\n<li><p>User logs in</p>\n</li>\n<li><p>Server creates a session in Redis</p>\n</li>\n<li><p>Session ID sent to client (HTTP-only cookie)</p>\n</li>\n<li><p>Client sends cookie automatically</p>\n</li>\n<li><p>Server validates session with Redis on each request</p>\n</li>\n</ol>\n<p><strong>Pros</strong></p>\n<ul>\n<li><p>Immediate session invalidation</p>\n</li>\n<li><p>Server-controlled security (e.g., secure cookies)</p>\n</li>\n</ul>\n<p><strong>Cons</strong></p>\n<ul>\n<li><p>Can require sticky sessions for scalability</p>\n</li>\n<li><p>Needs session storage</p>\n</li>\n</ul>\n","_postman_id":"e7deceb4-c941-433b-966c-76a1e1dabd02"},{"name":"Hybrid","item":[{"name":"register","id":"5412b77e-659c-4e07-ae48-c5965393aeac","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\r\n  \"email\": \"3user@example.com\",\r\n  \"password\": \"password123\",\r\n  \"name\": \"Hybrid User\"\r\n}","options":{"raw":{"language":"json"}}},"url":"http://localhost:3000/auth/hybrid/register","urlObject":{"protocol":"http","port":"3000","path":["auth","hybrid","register"],"host":["localhost"],"query":[],"variable":[]}},"response":[{"id":"8cfcbe4d-d995-475c-8d2a-2aae8fa539d6","name":"register","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\r\n  \"email\": \"3user@example.com\",\r\n  \"password\": \"password123\",\r\n  \"name\": \"Hybrid User\"\r\n}","options":{"raw":{"language":"json"}}},"url":"http://localhost:3000/auth/hybrid/register"},"status":"Created","code":201,"_postman_previewlanguage":"Text","header":[{"key":"X-Powered-By","value":"Express"},{"key":"Vary","value":"Origin"},{"key":"Access-Control-Allow-Credentials","value":"true"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"172"},{"key":"ETag","value":"W/\"ac-NFRDkia6qSVmhJlNpQkpdJFXyFk\""},{"key":"Date","value":"Wed, 28 Jan 2026 23:35:59 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"id\": \"dd682641-311c-4fd6-ae41-6ca3ccc62260\",\n    \"email\": \"3user@example.com\",\n    \"name\": \"Hybrid User\",\n    \"createdAt\": \"2026-01-28T22:36:01.638Z\",\n    \"updatedAt\": \"2026-01-28T22:36:01.638Z\"\n}"}],"_postman_id":"5412b77e-659c-4e07-ae48-c5965393aeac"},{"name":"login","id":"44e8d308-0f79-4887-a3c6-a09a6d036ada","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\r\n  \"email\": \"3user@example.com\",\r\n  \"password\": \"password123\"\r\n}","options":{"raw":{"language":"json"}}},"url":"http://localhost:3000/auth/hybrid/login","description":"<p><strong>Key Difference:</strong> This token contains a <code>jti</code> (JWT ID) that's validated against Redis whitelist.</p>\n","urlObject":{"protocol":"http","port":"3000","path":["auth","hybrid","login"],"host":["localhost"],"query":[],"variable":[]}},"response":[{"id":"21e2de2c-e711-43d0-94f7-225b89f1ee74","name":"login","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\r\n  \"email\": \"3user@example.com\",\r\n  \"password\": \"password123\"\r\n}","options":{"raw":{"language":"json"}}},"url":"http://localhost:3000/auth/hybrid/login"},"status":"Created","code":201,"_postman_previewlanguage":"Text","header":[{"key":"X-Powered-By","value":"Express"},{"key":"Vary","value":"Origin"},{"key":"Access-Control-Allow-Credentials","value":"true"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"512"},{"key":"ETag","value":"W/\"200-f2QqyrKgjLSKd7sSylxnZgW67Kw\""},{"key":"Date","value":"Wed, 28 Jan 2026 23:37:09 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"access_token\": \"{{vault:json-web-token}}\",\n    \"user\": {\n        \"id\": \"dd682641-311c-4fd6-ae41-6ca3ccc62260\",\n        \"email\": \"3user@example.com\",\n        \"name\": \"Hybrid User\",\n        \"createdAt\": \"2026-01-28T22:36:01.638Z\",\n        \"updatedAt\": \"2026-01-28T22:36:01.638Z\"\n    }\n}"}],"_postman_id":"44e8d308-0f79-4887-a3c6-a09a6d036ada"},{"name":"profile","id":"d719671a-9e6e-4f51-8e6f-b7224976d70c","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{vault:authorization-secret}}"}]},"isInherited":false},"method":"GET","header":[],"url":"http://localhost:3000/auth/hybrid/profile","urlObject":{"protocol":"http","port":"3000","path":["auth","hybrid","profile"],"host":["localhost"],"query":[],"variable":[]}},"response":[{"id":"104a52fa-21b6-4f4d-8c82-580484e10fe5","name":"profile","originalRequest":{"method":"GET","header":[],"url":"http://localhost:3000/auth/hybrid/profile"},"status":"OK","code":200,"_postman_previewlanguage":"Text","header":[{"key":"X-Powered-By","value":"Express"},{"key":"Vary","value":"Origin"},{"key":"Access-Control-Allow-Credentials","value":"true"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"285"},{"key":"ETag","value":"W/\"11d-up/abkE2JowuXNa/mVh/OsRnNTc\""},{"key":"Date","value":"Wed, 28 Jan 2026 23:38:39 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Hybrid Authentication successful\",\n    \"user\": {\n        \"userId\": \"dd682641-311c-4fd6-ae41-6ca3ccc62260\",\n        \"email\": \"3user@example.com\",\n        \"name\": \"Hybrid User\",\n        \"tokenId\": \"6932e7d5-7588-489e-951e-f5d2f2e93ac6\"\n    },\n    \"strategy\": \"hybrid\",\n    \"note\": \"Token is validated AND checked against Redis whitelist\"\n}"}],"_postman_id":"d719671a-9e6e-4f51-8e6f-b7224976d70c"},{"name":"logout","id":"b91068db-9f02-4875-acb7-27cbfcad3498","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{vault:authorization-secret}}"}]},"isInherited":false},"method":"POST","header":[],"url":"http://localhost:3000/auth/hybrid/logout","description":"<p>Token is removed from Redis whitelist. Future requests with this token will fail.\nTest: Try calling /auth/hybrid/profile again with the same token - it should fail with 401!</p>\n","urlObject":{"protocol":"http","port":"3000","path":["auth","hybrid","logout"],"host":["localhost"],"query":[],"variable":[]}},"response":[{"id":"3f598f42-0355-4509-8e07-fd3864fae170","name":"logout","originalRequest":{"method":"POST","header":[],"url":"http://localhost:3000/auth/hybrid/logout"},"status":"Created","code":201,"_postman_previewlanguage":"Text","header":[{"key":"X-Powered-By","value":"Express"},{"key":"Vary","value":"Origin"},{"key":"Access-Control-Allow-Credentials","value":"true"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"62"},{"key":"ETag","value":"W/\"3e-gFljDx3NbkG553SkOF/eIiaMWrw\""},{"key":"Date","value":"Wed, 28 Jan 2026 23:39:51 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Logout successful. Token removed from whitelist.\"\n}"},{"id":"02843044-92c7-4a8b-ba1d-fa24fe2b76e5","name":"second-attempt","originalRequest":{"method":"POST","header":[],"url":"http://localhost:3000/auth/hybrid/logout"},"status":"Unauthorized","code":401,"_postman_previewlanguage":null,"header":[{"key":"X-Powered-By","value":"Express"},{"key":"Vary","value":"Origin"},{"key":"Access-Control-Allow-Credentials","value":"true"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"78"},{"key":"ETag","value":"W/\"4e-mbURCyRBYgPRSz4+jQin0wAx230\""},{"key":"Date","value":"Sun, 01 Feb 2026 14:36:02 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Token is not whitelisted\",\n    \"error\": \"Unauthorized\",\n    \"statusCode\": 401\n}"}],"_postman_id":"b91068db-9f02-4875-acb7-27cbfcad3498"}],"id":"934e3ef4-ef6c-4561-af77-26ee278e83b0","description":"<p>Leverages JWT for stateless authentication but stores token IDs in Redis whitelist for revocation.</p>\n<p><strong>Flow:</strong></p>\n<ol>\n<li><p>User logs in, receives JWT</p>\n</li>\n<li><p>Token ID stored in Redis whitelist</p>\n</li>\n<li><p>Each request: server checks JWT validity <em>and</em> Redis whitelist</p>\n</li>\n<li><p>Logout removes token from whitelist</p>\n</li>\n</ol>\n<p><strong>Pros</strong></p>\n<ul>\n<li><p>Scalable as JWT</p>\n</li>\n<li><p>Immediate revocation</p>\n</li>\n</ul>\n<p><strong>Cons</strong></p>\n<ul>\n<li><p>Redis lookup on each request</p>\n</li>\n<li><p>More complex setup</p>\n</li>\n</ul>\n","_postman_id":"934e3ef4-ef6c-4561-af77-26ee278e83b0"},{"name":"Token-rotation","item":[{"name":"register","id":"1142b93d-6774-48dc-95c4-c1fb0116affe","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\r\n  \"email\": \"4user@example.com\",\r\n  \"password\": \"password123\",\r\n  \"name\": \"Refresh User\"\r\n}\r\n","options":{"raw":{"language":"json"}}},"url":"http://localhost:3000/auth/refresh/register","urlObject":{"protocol":"http","port":"3000","path":["auth","refresh","register"],"host":["localhost"],"query":[],"variable":[]}},"response":[{"id":"7b3aa234-98fa-48a4-8dfa-3714fbd76463","name":"register","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\r\n  \"email\": \"4user@example.com\",\r\n  \"password\": \"password123\",\r\n  \"name\": \"Refresh User\"\r\n}\r\n","options":{"raw":{"language":"json"}}},"url":"http://localhost:3000/auth/refresh/register"},"status":"Created","code":201,"_postman_previewlanguage":"Text","header":[{"key":"X-Powered-By","value":"Express"},{"key":"Vary","value":"Origin"},{"key":"Access-Control-Allow-Credentials","value":"true"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"173"},{"key":"ETag","value":"W/\"ad-p6N8pRyEWgRGn27kubh8hSjTv5E\""},{"key":"Date","value":"Wed, 28 Jan 2026 23:43:50 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"id\": \"daf3eea4-c822-4a3a-92f7-5cdfe092861a\",\n    \"email\": \"4user@example.com\",\n    \"name\": \"Refresh User\",\n    \"createdAt\": \"2026-01-28T22:43:51.344Z\",\n    \"updatedAt\": \"2026-01-28T22:43:51.344Z\"\n}"}],"_postman_id":"1142b93d-6774-48dc-95c4-c1fb0116affe"},{"name":"login","id":"3194178c-3cd1-400c-89d4-8d1e0cd91750","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\r\n  \"email\": \"4user@example.com\",\r\n  \"password\": \"password123\"\r\n  \r\n}","options":{"raw":{"language":"json"}}},"url":"http://localhost:3000/auth/refresh/login","description":"<p>Save both tokens:</p>\n<p><code>access_token</code> - expires in 15 minutes<br /><code>refresh_token</code> - expires in 7 days</p>\n","urlObject":{"protocol":"http","port":"3000","path":["auth","refresh","login"],"host":["localhost"],"query":[],"variable":[]}},"response":[{"id":"2bb2317d-39cb-48a4-8d2d-232cd45b8389","name":"login","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\r\n  \"email\": \"4user@example.com\",\r\n  \"password\": \"password123\"\r\n  \r\n}","options":{"raw":{"language":"json"}}},"url":"http://localhost:3000/auth/refresh/login"},"status":"Created","code":201,"_postman_previewlanguage":"Text","header":[{"key":"X-Powered-By","value":"Express"},{"key":"Vary","value":"Origin"},{"key":"Access-Control-Allow-Credentials","value":"true"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"826"},{"key":"ETag","value":"W/\"33a-lkLGMlnit/X3J++Elk6LOKAFfFg\""},{"key":"Date","value":"Wed, 28 Jan 2026 23:45:44 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"access_token\": \"{{vault:json-web-token}}\",\n    \"refresh_token\": \"{{vault:json-web-token}}\",\n    \"user\": {\n        \"id\": \"daf3eea4-c822-4a3a-92f7-5cdfe092861a\",\n        \"email\": \"4user@example.com\",\n        \"name\": \"Refresh User\",\n        \"createdAt\": \"2026-01-28T22:43:51.344Z\",\n        \"updatedAt\": \"2026-01-28T22:43:51.344Z\"\n    }\n}"}],"_postman_id":"3194178c-3cd1-400c-89d4-8d1e0cd91750"},{"name":"profile","id":"097eb993-324c-41b3-8deb-5133f50c47b8","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{vault:authorization-secret}}"}]},"isInherited":false},"method":"GET","header":[],"url":"http://localhost:3000/auth/refresh/profile","urlObject":{"protocol":"http","port":"3000","path":["auth","refresh","profile"],"host":["localhost"],"query":[],"variable":[]}},"response":[{"id":"be4d53c2-e3c6-4f32-a6ae-8d99b27c0823","name":"profile","originalRequest":{"method":"GET","header":[],"url":"http://localhost:3000/auth/refresh/profile"},"status":"OK","code":200,"_postman_previewlanguage":"Text","header":[{"key":"X-Powered-By","value":"Express"},{"key":"Vary","value":"Origin"},{"key":"Access-Control-Allow-Credentials","value":"true"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"222"},{"key":"ETag","value":"W/\"de-/wI1ZAwJZFN3AyFl78NmSssmUeY\""},{"key":"Date","value":"Wed, 28 Jan 2026 23:47:20 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Access token validated\",\n    \"user\": {\n        \"userId\": \"daf3eea4-c822-4a3a-92f7-5cdfe092861a\",\n        \"email\": \"4user@example.com\",\n        \"name\": \"Refresh User\"\n    },\n    \"strategy\": \"refresh-token\",\n    \"note\": \"Use short-lived access token for API calls\"\n}"}],"_postman_id":"097eb993-324c-41b3-8deb-5133f50c47b8"},{"name":"refresh-token","id":"cf26f2ac-21cf-4d1e-b6c6-36011eb9041a","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{vault:authorization-secret}}"}]},"isInherited":false},"method":"POST","header":[],"url":"http://localhost:3000/auth/refresh/refresh","description":"<p>Old refresh token is invalidated<br />New refresh token is issued (token rotation)<br />If old refresh token is used again, it fails (detects theft)</p>\n","urlObject":{"protocol":"http","port":"3000","path":["auth","refresh","refresh"],"host":["localhost"],"query":[],"variable":[]}},"response":[{"id":"19f7e5e2-be9f-430c-abc2-e257459ab429","name":"refresh-token","originalRequest":{"method":"POST","header":[],"url":"http://localhost:3000/auth/refresh/refresh"},"status":"Created","code":201,"_postman_previewlanguage":"Text","header":[{"key":"X-Powered-By","value":"Express"},{"key":"Vary","value":"Origin"},{"key":"Access-Control-Allow-Credentials","value":"true"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"645"},{"key":"ETag","value":"W/\"285-b1K5TEgTGH7VYJA6S2N4j5tzhx8\""},{"key":"Date","value":"Wed, 28 Jan 2026 23:49:39 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"access_token\": \"{{vault:json-web-token}}\",\n    \"refresh_token\": \"{{vault:json-web-token}}\"\n}"}],"_postman_id":"cf26f2ac-21cf-4d1e-b6c6-36011eb9041a"}],"id":"67769ff1-58ac-4f42-82d5-f5d0bc75133d","description":"<p>The strategy: short-lived access tokens for requests, long-lived refresh tokens for renewal.</p>\n<p><strong>Flow:</strong></p>\n<ol>\n<li><p>Login issues access (e.g., 15m) &amp; refresh tokens (e.g., 7d)</p>\n</li>\n<li><p>API requests use access token</p>\n</li>\n<li><p>Expired access token can be renewed with refresh token</p>\n</li>\n<li><p>Server issues new access (&amp; optionally refresh) tokens on renewal</p>\n</li>\n</ol>\n<p><strong>Token Rotation:</strong></p>\n<ul>\n<li><p>On refresh, the server issues a new refresh token and invalidates the old</p>\n</li>\n<li><p>Attempts to reuse an old refresh token can be detected (token theft)</p>\n</li>\n</ul>\n<p><strong>Pros</strong></p>\n<ul>\n<li><p>Minimal damage if access token compromised</p>\n</li>\n<li><p>Refresh tokens can be revoked for security</p>\n</li>\n</ul>\n<p><strong>Cons</strong></p>\n<ul>\n<li><p>More complex implementation</p>\n</li>\n<li><p>Secure storage for refresh tokens required</p>\n</li>\n</ul>\n","_postman_id":"67769ff1-58ac-4f42-82d5-f5d0bc75133d"}]}