Lewati ke konten

Bearer Auth

Deserve membawa Basic Auth tapi tidak ada middleware Bearer, dan pemisahan antara keduanya adalah intinya.

Kenapa Tidak Dibawa

Bearer hanyalah sebuah amplop. Header Authorization: Bearer <token> membawa token, dan apa yang dianggap token valid berubah seiring ekosistem. Satu layanan memverifikasi tanda tangan JWT, lain mengambil kunci publik berputar dari endpoint JWKS, lain memanggil API introspeksi untuk token buram, dan algoritma penanda bisa RS256, ES256, atau HS256.

Menanam salah satu pilihan itu akan mengunci setiap proyek ke satu skema. Ketika spesifikasi bergerak atau sebuah tim memutar kunci dengan cara berbeda, jawaban bawaan itu berubah jadi kandang ketimbang bantuan. Jadi keputusannya adalah membiarkan verifikasi terbuka dan membiarkan developer membawa skema yang dibutuhkan kasusnya.

Kenapa Basic Auth Dibawa Tapi Bearer Tidak

Basic Auth adalah satu skema tetap. Header membawa username dan password base64, pengecekannya adalah perbandingan waktu konstan terhadap sebuah daftar, dan tak ada yang perlu dipilih. Stabilitas itulah yang membuatnya cocok di dalam framework.

Bearer sebaliknya. Format token, tanda tangan, dan sumber kepercayaan semuanya berbeda, jadi tak ada satu pengecekan untuk dibawa. Kedua skema membaca header Authorization yang sama, tapi hanya satu yang punya jawaban benar tunggal.

Bagian yang Sudah Ada

Penjaga token adalah komposisi kecil di atas bagian yang sudah ada:

Sebuah Penjaga Bearer

Middleware ini menarik token dari header, memverifikasinya, dan menyimpan hasilnya untuk handler berikutnya. Placeholder verifyToken mewakili skema pilihan, sebuah pengecekan JWT, lookup JWKS, atau panggilan introspeksi.

typescript
router
.
use
(async (
ctx
,
next
) => {
const
header
=
ctx
.
header
('authorization')
const
spaceIndex
=
header
?
header
.
indexOf
(' ') : -1
const
scheme
=
spaceIndex
> 0 ?
header
!.
slice
(0,
spaceIndex
) : ''
// Tolak apa pun yang bukan Bearer if (
scheme
.
toLowerCase
() !== 'bearer') {
return await
ctx
.
handleError
(401, new
Error
('Missing Bearer token'))
} // Verifikasi dengan skema pilihan const
token
=
header
!.
slice
(
spaceIndex
+ 1).
trim
()
const
claims
= await
verifyToken
(
token
)
if (!
claims
) {
return await
ctx
.
handleError
(401, new
Error
('Invalid token'))
} // Serahkan identitas ke handler
ctx
.
state
.
userId
=
claims
.
userId
return await
next
()
}) await
router
.
serve
(8000)

Handler lalu membaca identitas langsung dari state, tanpa parsing token sendiri.

typescript
export function 
GET
(
ctx
:
Context
): Response {
// Baca apa yang disimpan penjaga const
userId
=
ctx
.
state
.
userId
return
ctx
.
send
.
json
({
userId
})
}

Mengarahkan Kegagalan Lewat Satu Handler

Penjaga di atas mengembalikan 401 dari dalam middleware. Untuk mengirim setiap kegagalan auth lewat satu tempat, bungkus middleware dengan WrapMware dan lempar saat ditolak, lalu bentuk balasannya dengan router.catch().

typescript
// Lemparan sampai router.catch saat dibungkus
const 
bearer
=
WrapMware
('Bearer', async (
ctx
:
Context
,
next
) => {
const
header
=
ctx
.
header
('authorization')
if (!
header
?.
toLowerCase
().
startsWith
('bearer ')) {
throw new
Error
('Missing Bearer token')
} const
claims
= await
verifyToken
(
header
.
slice
(7).
trim
())
if (!
claims
) {
throw new
Error
('Invalid token')
}
ctx
.
state
.
userId
=
claims
.
userId
return await
next
()
}) // Terapkan penjaga dan bentuk error
router
.
use
(
bearer
)
router
.
catch
((
ctx
,
err
) =>
ctx
.
send
.
json
({
error
:
err
.
error
?.
message
}, {
status
: 401 }))

Ini pola pembungkusan yang sama dipakai Basic Auth secara internal, kini membawa pengecekan token alih-alih perbandingan kredensial.

Menjaga Hanya Sebagian Rute

Penjaga token sering cocok di prefix API sementara halaman publik tetap terbuka. Middleware per-path membatasi pengecekan ke satu prefix, bentuk yang sama ditunjukkan di middleware global.

typescript
// Jaga hanya rute /api
router
.
use
('/api', async (
ctx
,
next
) => {
const
header
=
ctx
.
header
('authorization')
const
claims
=
header
?.
toLowerCase
().
startsWith
('bearer ')
? await
verifyToken
(
header
.
slice
(7).
trim
())
: null if (!
claims
) {
return await
ctx
.
handleError
(401, new
Error
('Invalid token'))
}
ctx
.
state
.
userId
=
claims
.
userId
return await
next
()
})

Untuk session sisi server yang ditandatangani framework alih-alih token, lihat middleware session.

Dirilis di bawah Lisensi MIT.