Use Cases

Cara Membangun Sistem Authentication dengan Claude Code (JWT dan OAuth)

Cara Membangun Sistem Authentication dengan Claude Code (JWT dan OAuth). Panduan praktis dengan contoh kode.

Keuntungan Menggunakan Claude Code untuk Membangun Sistem Authentication

Authentication adalah fungsionalitas yang langsung terkait keamanan, dan kesalahan implementasi bisa menyebabkan kerentanan serius. Claude Code men-generate implementasi dengan mempertimbangkan best practice keamanan, dan juga menyarankan penanggulangan terhadap vektor serangan yang sering terlewat.

Implementasi JWT Authentication

> Implementasikan JWT authentication dengan Express + TypeScript.
> Dengan metode 2-token: access token (15 menit) dan refresh token (7 hari).
> Kelola refresh token dengan httpOnly cookie.

Service Authentication

import jwt from 'jsonwebtoken';
import bcrypt from 'bcrypt';
import { prisma } from './db';

const ACCESS_TOKEN_SECRET = process.env.ACCESS_TOKEN_SECRET!;
const REFRESH_TOKEN_SECRET = process.env.REFRESH_TOKEN_SECRET!;

interface TokenPayload {
  userId: string;
  email: string;
}

export class AuthService {
  async register(email: string, password: string, name: string) {
    const existing = await prisma.user.findUnique({ where: { email } });
    if (existing) throw new Error('Email already registered');

    const hashedPassword = await bcrypt.hash(password, 12);
    const user = await prisma.user.create({
      data: { email, password: hashedPassword, name },
    });

    return this.generateTokens({ userId: user.id, email: user.email });
  }

  async login(email: string, password: string) {
    const user = await prisma.user.findUnique({ where: { email } });
    if (!user) throw new Error('Invalid credentials');

    const valid = await bcrypt.compare(password, user.password);
    if (!valid) throw new Error('Invalid credentials');

    return this.generateTokens({ userId: user.id, email: user.email });
  }

  async refreshToken(token: string) {
    const payload = jwt.verify(token, REFRESH_TOKEN_SECRET) as TokenPayload;

    // Konfirmasi validitas refresh token di DB
    const stored = await prisma.refreshToken.findFirst({
      where: { token, userId: payload.userId, revoked: false },
    });
    if (!stored) throw new Error('Invalid refresh token');

    // Invalidasi token lama (rotasi token)
    await prisma.refreshToken.update({
      where: { id: stored.id },
      data: { revoked: true },
    });

    return this.generateTokens(payload);
  }

  private async generateTokens(payload: TokenPayload) {
    const accessToken = jwt.sign(payload, ACCESS_TOKEN_SECRET, {
      expiresIn: '15m',
    });
    const refreshToken = jwt.sign(payload, REFRESH_TOKEN_SECRET, {
      expiresIn: '7d',
    });

    await prisma.refreshToken.create({
      data: { token: refreshToken, userId: payload.userId },
    });

    return { accessToken, refreshToken };
  }
}

Middleware Authentication

import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';

export function authMiddleware(req: Request, res: Response, next: NextFunction) {
  const header = req.headers.authorization;
  if (!header?.startsWith('Bearer ')) {
    return res.status(401).json({ error: 'No token provided' });
  }

  const token = header.slice(7);

  try {
    const payload = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET!);
    req.user = payload as TokenPayload;
    next();
  } catch (err) {
    return res.status(401).json({ error: 'Invalid or expired token' });
  }
}

Konfigurasi Router

import { Router } from 'express';
import { AuthService } from './auth-service';

const router = Router();
const auth = new AuthService();

router.post('/register', async (req, res) => {
  try {
    const { accessToken, refreshToken } = await auth.register(
      req.body.email, req.body.password, req.body.name
    );
    res.cookie('refreshToken', refreshToken, {
      httpOnly: true,
      secure: true,
      sameSite: 'strict',
      maxAge: 7 * 24 * 60 * 60 * 1000,
    });
    res.json({ accessToken });
  } catch (err) {
    res.status(400).json({ error: (err as Error).message });
  }
});

router.post('/login', async (req, res) => {
  try {
    const { accessToken, refreshToken } = await auth.login(
      req.body.email, req.body.password
    );
    res.cookie('refreshToken', refreshToken, {
      httpOnly: true,
      secure: true,
      sameSite: 'strict',
      maxAge: 7 * 24 * 60 * 60 * 1000,
    });
    res.json({ accessToken });
  } catch (err) {
    res.status(401).json({ error: 'Invalid credentials' });
  }
});

router.post('/refresh', async (req, res) => {
  try {
    const token = req.cookies.refreshToken;
    const { accessToken, refreshToken } = await auth.refreshToken(token);
    res.cookie('refreshToken', refreshToken, {
      httpOnly: true,
      secure: true,
      sameSite: 'strict',
      maxAge: 7 * 24 * 60 * 60 * 1000,
    });
    res.json({ accessToken });
  } catch (err) {
    res.status(401).json({ error: 'Invalid refresh token' });
  }
});

export default router;

Integrasi OAuth (Google)

> Tambahkan Google login dengan PassportJS. Integrasikan dengan JWT authentication yang sudah ada.
import passport from 'passport';
import { Strategy as GoogleStrategy } from 'passport-google-oauth20';

passport.use(new GoogleStrategy({
  clientID: process.env.GOOGLE_CLIENT_ID!,
  clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
  callbackURL: '/auth/google/callback',
}, async (accessToken, refreshToken, profile, done) => {
  let user = await prisma.user.findFirst({
    where: { providerId: profile.id, provider: 'google' },
  });

  if (!user) {
    user = await prisma.user.create({
      data: {
        email: profile.emails![0].value,
        name: profile.displayName,
        provider: 'google',
        providerId: profile.id,
      },
    });
  }

  done(null, user);
}));

Checklist Keamanan

Kamu bisa meminta Claude Code melakukan audit keamanan dengan prompt berikut.

> Review kode terkait authentication dari perspektif keamanan.
> Periksa berdasarkan OWASP Top 10.

Item pemeriksaan utama:

  • Apakah menggunakan bcrypt untuk password hashing
  • Apakah JWT secret key cukup panjang
  • Apakah rotasi refresh token diimplementasikan
  • Apakah perlindungan CSRF diterapkan
  • Apakah rate limiting diatur

Untuk mempertahankan kualitas kode termasuk keamanan, Otomasi Refactoring juga efektif. Dengan mendokumentasikan kebijakan konfigurasi authentication di CLAUDE.md, Claude Code akan men-generate kode yang konsisten.

Summary

Dengan Claude Code, kamu bisa membangun sistem authentication yang robust termasuk JWT authentication dan integrasi OAuth secara efisien. Karena kode di-generate dengan mempertimbangkan best practice keamanan, kerentanan yang sering terlewat juga lebih mudah ditangani. Pastikan untuk selalu menerapkan manajemen secret key yang aman dan komunikasi HTTPS di lingkungan produksi.

Untuk detail, lihat Dokumentasi Resmi Anthropic.

#Claude Code #authentication #JWT #OAuth #security