In this lesson, you will learn how to verify the end-to-end identity lifecycle by treating authentication as a multi-step integration process rather than isolated unit tests.
Beyond Unit Testing
While unit tests verify if a single password hashing function works, integration tests ensure your auth system actually "breathes." A robust integration test simulates a real user journey: Registration → Login → Session Usage → Revocation. If any link in this chain breaks, your authentication logic fails the user, regardless of how secure individual components are.
Orchestrating the Lifecycle
To test this effectively in Node.js, use a tool like supertest to hit your actual API endpoints against a test-specific database. The goal is to move through the identity lifecycle programmatically:
- Registration: Send a POST request to your
/registerendpoint. - Authentication: Attempt to log in with those credentials to receive a token (or set a cookie).
- Authorization: Use that token to access a protected route (e.g.,
/profile) to verify the token is valid. - Revocation: Call your
/logoutor/revokeendpoint. - Verification: Attempt to access the protected route again with the now-invalidated token to ensure it returns a
401 Unauthorized.
it('should perform a full auth lifecycle', async () => {
const credentials = { email: 'test@example.com', password: 'Password123!' };
// 1. Register
await request(app).post('/auth/register').send(credentials);
// 2. Login & 3. Access
const loginRes = await request(app).post('/auth/login').send(credentials);
const token = loginRes.body.token;
const profile = await request(app).get('/user/profile').set('Authorization', `Bearer ${token}`);
expect(profile.status).toBe(200);
// 4. Revocation
await request(app).post('/auth/revoke').set('Authorization', `Bearer ${token}`);
// 5. Verification
const protectedRes = await request(app).get('/user/profile').set('Authorization', `Bearer ${token}`);
expect(protectedRes.status).toBe(401);
});
By chaining these requests, you catch subtle bugs like forgotten cache clears during logout or misconfigured token expiration logic. This sequence guarantees that your entire identity stack—from database persistence to middleware guards—works in harmony.
Key Takeaway: Integration tests must follow the entire user lifecycle, verifying not just that authentication works, but that revocation effectively terminates access.