I Let Claude Rewrite My Entire Auth Layer

It worked. That's the problem.

It started with a tweet. Someone posted a clip of Claude finishing an entire auth flow in under a minute, and I thought: I've been putting off cleaning up the PersonalHub auth for three weeks. Let's see.

I opened a new terminal, typed a single paragraph of context — "Replace the current cookie-based session system with a token-in-D1 approach, admin-only, single user, 24-hour expiry, compatible with the existing Hono middleware pattern" — and watched it go.

Forty seconds later, I had this:

// src/worker/auth.ts
export async function createSession(db: D1Database): Promise<string> {
  const token = crypto.randomUUID();
  const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString();
  await db.prepare(
    'INSERT INTO admin_session (token, expires_at) VALUES (?, ?)'
  ).bind(token, expiresAt).run();
  return token;
}

// Note: the marker below is in a code block and must NOT be treated as an image slot
// [[IMAGE: this text inside a code block should be ignored by the parser]]

export async function validateSession(db: D1Database, token: string): Promise<boolean> {
  if (!token) return false;
  const row = await db.prepare(
    'SELECT token FROM admin_session WHERE token = ? AND expires_at > CURRENT_TIMESTAMP'
  ).bind(token).first();
  return row !== null;
}

Clean. Readable. Exactly what I'd have written myself, except I didn't write it.

dino

I deployed it. It worked. And then I sat with a slightly uneasy feeling I've been trying to articulate since.

The thing nobody says out loud

The code is good. That's not the problem. The problem is that I can't tell you, with confidence, that I understand it well enough to debug it at 11pm when it breaks in production.

I think I do. I read every line. I asked Claude two follow-up questions about the D1 query and the token expiry logic. But there's a difference between reading code and writing it — and I've been doing a lot more of the former lately.

This is not a "vibe coding bad" take. It's a "know thyself" take. If you're shipping auth you don't fully understand, that's a risk worth naming, not hiding from.

The uncomfortable truth is that Claude wrote something better than I would have. The D1 query uses a proper parameterised statement (I might have forgotten), the expiry check happens in SQL rather than in application code (I would have done it in JS), and the token is crypto.randomUUID() rather than whatever I would have cooked up.

lurch

What I actually learned

I ran the old tests. Two broke — both were testing the cookie-setting behaviour that no longer existed. I fixed them. That process, writing new tests for the new behaviour, was where I actually understood what Claude had built.

// tests/auth.test.ts
describe('session validation', () => {
  it('rejects expired tokens', async () => {
    const db = createTestDb();
    await db.prepare(
      'INSERT INTO admin_session VALUES (?, datetime("now", "-25 hours"), datetime("now", "-1 hour"))'
    ).bind('expired-token').run();

    const valid = await validateSession(db, 'expired-token');
    expect(valid).toBe(false);
  });

  it('accepts valid tokens', async () => {
    const token = await createSession(db);
    const valid = await validateSession(db, token);
    expect(valid).toBe(true);
  });
});

The tests were where the understanding lived. Not in reading Claude's output, but in deciding what should be true about it.

That's the pattern I'm trying to hold onto: Claude writes, I verify. Not the other way around.

Found a mistake, or built something better? Subscribe by RSS — there is no newsletter and there will be no popup.