Go ile JWT Authentication: Access Token, Refresh Token ve Güvenli Saklama
JWT (JSON Web Token), mikroservislerde ve tek parça uygulamalarda kimlik taşımak için en yaygın formatlardan biri. Ancak “JWT kullandık, güvenlik bitti” demek mümkün değil: saklama, süre, yenileme ve iptal stratejisi olmadan üretim ortamında risk büyür.
Bu yazı, Go ile JWT authentication kurmak isteyen geliştiriciler için access / refresh ayrımına ve güvenli pratiklere odaklanır.
JWT kısa hatırlatma
Üç parça: header.payload.signature. İmzayı sadece sunucu (veya güvenilir anahtar sahibi) üretir; payload genelde base64url ile kodlanmış JSON’dur ve şifrelenmiş değildir — içeriği herkes okuyabilir; bu yüzden hassas veri koymayın.
Access token vs refresh token
| Access token | Refresh token | |
|---|---|---|
| Ömür | Kısa (dakika–saat) | Uzun (gün–hafta), ama dikkatli |
| Kullanım | API isteklerinde | Yeni access almak için |
| Saklama | Bellek / kısa süreli | Güvenli depo, rotasyon |
Kural: Access token çalınsa bile pencerenin kısa olması zararı sınırlar. Refresh token çok daha kritiktir.
Go’da imzalama ve doğrulama
Yaygın kütüphane: github.com/golang-jwt/jwt/v5.
import "github.com/golang-jwt/jwt/v5"
type Claims struct {
UserID string `json:"uid"`
jwt.RegisteredClaims
}
func SignAccess(userID string, secret []byte, ttl time.Duration) (string, error) {
claims := Claims{
UserID: userID,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(ttl)),
IssuedAt: jwt.NewNumericDate(time.Now()),
},
}
t := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return t.SignedString(secret)
}
Doğrulama:
func Parse(tokenString string, secret []byte) (*Claims, error) {
tok, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(t *jwt.Token) (interface{}, error) {
return secret, nil
})
if err != nil { return nil, err }
if c, ok := tok.Claims.(*Claims); ok && tok.Valid {
return c, nil
}
return nil, jwt.ErrSignatureInvalid
}
HS256 paylaşımlı giz; mikroservislerde çoklu servis için RS256 (asimetrik) ile public key ile doğrulama sık tercih edilir.
Refresh token’ı güvenli tutma
Yapmayın: Refresh token’ı localStorage’a yazmak (XSS riski).
Daha iyi:
- HttpOnly + Secure + SameSite çerezde refresh token
- Access token’ı kısa ömürlü tutup bellekte veya aynı çerez stratejisiyle vermek
- Refresh token rotation: Her kullanımda yeni refresh üret, eskiyi geçersiz kıl; çalınan eski token tek kullanımlık olmasın
Sunucu tarafında refresh kayıtlarını Redis veya veritabanında tutup iptal listesi (logout, şüpheli aktivite) uygulayın.
Yaygın hatalar
- Uzun ömürlü access token ve içinde fazla claim
- İmzayı doğrulamadan payload’a güvenmek
- Alg confusion: Sunucunun
alg: noneveya beklenmeyen algoritmaları kabul etmesi — kütüphane ayarlarını sıkılaştırın - Sızdırılmış secret — ortam değişkenleri ve secret manager kullanın
Özet
- Go ile JWT authentication için net bir access / refresh ayrımı ve kısa access ömrü şart.
- Refresh token’ı HttpOnly cookie + rotasyon ile koruyun.
- Üretimde mümkünse RS256 ve merkezi anahtar yönetimi düşünün.
Bu konu, rate limiting ve API güvenliği için Redis ile rate limiting yazısıyla birlikte düşünülmeli; giriş noktasında limit + kimlik birlikte çalışır.
İlgili Yazılar
gRPC vs REST: Ne Zaman Hangisini Kullanmalısın? Go ile Karşılaştırmalı Rehber
Mikroservislerde gRPC ve REST farkları; protobuf, HTTP/2, tarayıcı uyumu ve Go örnekleri. REST ile Go servis karşılaştırması için iç link.
Redis ile Rate Limiting: Go'da Token Bucket ve Sliding Window Implementasyonu
golang rate limiting için Redis tabanlı token bucket ve sliding window algoritmaları; Lua script, atomicity ve üretimde dikkat edilecek noktalar.
Go ile CLI Geliştirme: Komut Satırı Araçlarına Derinlemesine Rehber
flag ve Cobra ile alt komutlar, stdin/stdout, çıkış kodları, çapraz derleme ve test: üretim kalitesinde Go CLI geliştirmenin pratik rehberi.