Magic link menghilangkan password: user memasukkan email, server mengirim tautan sekali pakai. Klik tautan → langsung login. Slack, Notion, Substack memakai pola ini.
Keuntungan:
- Tidak ada password untuk dibobol, dihafalkan, atau di-phishing ulang
- Memanfaatkan email (yang sudah harus aman) sebagai faktor identitas
Kelemahan:
- Bergantung pada keamanan email provider
- UX: harus buka tab/app lain untuk klik link
- Serangan: phishing yang menyerupai email "magic link" asli
Alur lengkap:
1. User input email: "[email protected]"
2. Server generate token random (32 bytes), simpan hash + expiry + emailnya
3. Server kirim email: "Klik untuk login: https://app.com/auth/magic?token=xyz"
4. User klik link dalam 15 menit
5. Server cek: token valid? belum kadaluarsa? belum digunakan?
6. Jika valid: buat session + tandai token sebagai consumed
7. Redirect ke dashboard
Implementasi server:
async function requestMagicLink(email) {
const token = crypto.randomBytes(32).toString("hex");
const tokenHash = await bcrypt.hash(token, 10); // jangan simpan raw token!
const expiresAt = Date.now() + 15 * 60 * 1000; // 15 menit
await db.magicLinks.insert({
email, tokenHash, expiresAt, consumedAt: null,
});
await sendEmail(email, `https://app.com/auth/magic?token=${token}`);
}
async function verifyMagicLink(token) {
const records = await db.magicLinks.findByExpiryAfter(Date.now());
for (const record of records) {
if (record.consumedAt) continue;
if (await bcrypt.compare(token, record.tokenHash)) {
await db.magicLinks.markConsumed(record.id);
return record.email; // login berhasil
}
}
return null;
}
Aturan keamanan yang WAJIB:
1. Token hanya sekali pakai — setelah diklik, invalidate permanent. Jika klik lagi → error.
2. Short expiry — maksimal 15 menit. Token yang lama tersisa di inbox adalah liability.
3. Simpan hash, bukan token mentah — jika DB bocor, penyerang tidak dapat token valid.
4. Rate limiting per email — cegah spam email dan enumeration attack.
5. Token panjang (≥32 bytes random) — anti-brute force.
6. Constant-time comparison — cegah timing attack.
Bonus: session fixation
Setelah magic link berhasil, buat session ID baru (jangan reuse session sebelumnya). Ini mencegah skenario di mana penyerang "menyiapkan" session lalu mengundang korban login ke session itu.