SPRİNG SECURİTY VE JWT: AUTHENTİCATİON/AUTHORİZATİON KURGUSU VE YAYGIN TUZAKLAR
JWT ile güvenlik kurgusu kurmak “token üret ve gönder” kadar basit görünse de, authentication ve authorization sınırlarını doğru çizmediğinizde sistem hızla kırılganlaşır. Spring Security ise esnekliği nedeniyle hem çok güçlü hem de yanlış anlaşılmaya açık bir çerçevedir. Bu yazıda, JWT tabanlı akışı uçtan uca ele alıp üretimde sık rastlanan tuzakları, doğru yapı taşlarıyla birlikte netleştireceğiz.
Odak noktamız, Spring Security’nin modern yaklaşımı olan SecurityFilterChain üzerinden stateless (durumsuz) bir API güvenliği kurmak: token doğrulama, claim’lerin role/authority’ye çevrilmesi, endpoint bazlı yetki kuralları ve CORS/CSRF gibi çevresel başlıklar.
Makale boyunca “kopyala-çalıştır” beklentisi yerine, doğru mimari kararları destekleyen örnekler göreceksiniz. Daha kapsamlı Spring Boot güvenliği için Spring Boot Eğitimi içeriğine de göz atabilirsiniz.
Primary keyword: Spring Security JWT ile kimlik doğrulama ve yetkilendirme
Authentication vs Authorization: iki farklı problem
Authentication, kullanıcının “kim olduğunu” kanıtlama sürecidir: kullanıcı adı/şifre, SSO, OTP veya bir token ile doğrulama. Authorization ise doğrulanan kimliğin “ne yapabildiğini” belirler: rol, izin, scope ve kaynak bazlı kurallar.
JWT, çoğunlukla authentication sonucunda verilen bir bearer token olarak kullanılır; ancak token’ın içindeki claim’ler üzerinden authorization kararları da üretilebilir. Buradaki kritik nokta: authorization kararlarını sadece token içinden okumak yerine, servisler arası tutarlılığı bozmayacak şekilde kurgulamak.
Stateless yaklaşımın bedeli ve getirisi
Stateless API’lerde sunucu tarafında oturum tutulmaz; her istek kendini kanıtlar. Bu, yatayda ölçeklenmeyi kolaylaştırır ama token ömrü, iptal (revocation), anahtar yönetimi ve saat kayması gibi konuları daha önemli hale getirir.
- Token ömrünü kısa tutup refresh token ile dengelemek
- JWK/anahtar rotasyonu ile güvenli imzalama
- Clock skew toleransı ve tutarlı zaman kaynağı
- Claim doğrulama: issuer, audience, expiry, not-before

Spring Security’de JWT Resource Server yaklaşımı
Neden “kendi filtremini yazarım” yaklaşımı riskli?
JWT doğrulama, yalnızca imza kontrolü değildir. Doğru algoritma seçimi, header manipülasyonu, claim doğrulaması, anahtar seçimi (kid), hata yönetimi ve performans gibi konular bir araya gelince “minimal filtre” çözümleri üretimde sürpriz çıkarır. Spring’in OAuth2 Resource Server modülü, JWT doğrulama zincirini sağlam bir şekilde kurmanıza yardımcı olur.
SecurityFilterChain ile temel konfigürasyon
Aşağıdaki örnek, JWT doğrulayan bir Resource Server yaklaşımını gösterir. Yetkilendirme kuralları endpoint bazında tanımlanır ve API durumsuz hale getirilir.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableMethodSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/actuator/health").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
return http.build();
}
}Burada önemli detay: hasRole ile kontrol yapıyorsanız, Spring varsayılan olarak role değerini ROLE_ prefiksiyle eşleştirir. Token claim’leriniz “ADMIN” ise “ROLE_ADMIN” dönüşümü doğru yapılmazsa 403 hataları kaçınılmaz olur.
Claim’leri Authority’ye dönüştürme: rol/scope haritalama
En sık hata: claim adı ve formatı varsaymak
Kimlik sağlayıcınız “roles”, “role”, “authorities”, “scope” veya “scp” gibi farklı claim isimleri kullanabilir. Ayrıca claim bazen string, bazen dizi, bazen de boşlukla ayrılmış tek bir metin olur. Bu yüzden mapping katmanını açıkça tanımlamak güvenilir sonuç verir.
JwtAuthenticationConverter ile özelleştirme
Aşağıdaki örnek, “roles” claim’ini authority listesine çevirir ve ROLE_ prefiksini ekler. Böylece hasRole/hasAuthority kuralları tutarlı çalışır.
import java.util.Collection;
import java.util.stream.Collectors;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.stereotype.Component;
@Component
public class RolesClaimJwtConverter implements Converter<Jwt, AbstractAuthenticationToken> {
@Override
public AbstractAuthenticationToken convert(Jwt jwt) {
Collection<String> roles = jwt.getClaimAsStringList("roles");
Collection<GrantedAuthority> authorities = roles == null ? java.util.List.of()
: roles.stream()
.map(r -> r.startsWith("ROLE_") ? r : "ROLE_" + r)
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
return new JwtAuthenticationToken(jwt, authorities, jwt.getSubject());
}
}Bu yaklaşımın faydası, authorization kurallarının token üreticisine bağımlı “tahminlerle” değil, açık bir dönüştürme mantığıyla çalışmasıdır. Üretimde claim formatı değiştiğinde yalnızca converter katmanı güncellenir.

Token doğrulama derinliği: issuer, audience, expiry ve anahtar yönetimi
Sadece imzayı doğrulamak yetmez
İmza doğrulaması, token’ın bir anahtarla üretildiğini kanıtlar; fakat token’ın kime ve hangi amaçla verildiğini tek başına garanti etmez. Bu yüzden issuer (iss) ve audience (aud) kontrolleri, özellikle çoklu istemci ve çoklu servis mimarisinde kritik hale gelir.
JWK ve key rotation: “kid” ile doğru anahtar seçimi
Modern sağlayıcılar JWK endpoint’i üzerinden anahtarları yayınlar ve düzenli rotasyon yapar. Resource Server bu anahtarları cache’leyerek doğrulama yapar. Buradaki yaygın tuzaklar:
- JWK cache süresini aşırı uzun tutarak rotasyon sonrası doğrulama hatalarına yol açmak
- Tek anahtara bağımlı kalıp acil anahtar değişiminde servis kesintisi yaşamak
- Algoritma doğrulamasını gevşek bırakmak (ör. beklenmeyen alg kabul etmek)
Doğru kurguda, hem beklenen issuer/audience sabitlenir hem de algoritma ve anahtar seçimi netleşir. Ayrıca “token süresi doldu” ve “imza doğrulanamadı” gibi hata tipleri gözlemlenebilir olmalıdır; aksi halde hatayı kullanıcıya yanlış mesaj olarak yansıtma riski doğar.
CSRF, CORS ve “çalışıyor ama güvenli değil” senaryoları
CSRF ne zaman kapatılmalı, ne zaman düşünülmeli?
Stateless JWT ile korunan saf REST API’lerde, cookie tabanlı oturum kullanılmıyorsa CSRF çoğu senaryoda devre dışı bırakılır. Ancak aynı domain altında hem web oturumu hem API çağrıları varsa, “CSRF kapalı” kararı beklenmedik saldırı yüzeyi açabilir. Burada ana belirleyici, kimlik bilgisinin taşıma yöntemi (cookie mi, Authorization header mı) ve tarayıcı davranışlarıdır.
CORS’u “permitAll” sanmak
CORS bir yetkilendirme mekanizması değildir; tarayıcının çapraz origin isteklerine dair bir politikadır. Sunucu CORS başlıklarını doğru set etmiyorsa, istemci tarafında “Network error” görürsünüz; ama bu durum endpoint’in sunucu tarafında güvenli olduğu anlamına gelmez. Güvenlik kararları her zaman Spring Security kurallarıyla verilmelidir.
Üretimde sık görülen bir hata: CORS’u sadece development origin’ine göre ayarlayıp staging/production’da unutmak. Sonuç olarak kullanıcılar login olur ama API çağrıları tarayıcı tarafından bloklanır; ekipler sorunu JWT’de aramaya başlar.
Method Security ve kaynak bazlı yetkilendirme
Endpoint bazlı kurallar yetmezse
Endpoint bazlı authorization, çoğu uygulamada başlangıç için yeterlidir. Ancak “kendi kaydını görebilir”, “aynı tenant içindeki kaynaklara erişebilir” gibi kaynak bazlı ihtiyaçlar ortaya çıktığında, method security güçlü bir tamamlayıcıdır.
@PreAuthorize ile okunabilir kurallar
Örneğin kullanıcı, sadece kendi hesabına ait kaydı okuyabilsin. Token’dan gelen subject (sub) ya da bir kullanıcı id claim’i ile parametre eşleştirilir. Bu yaklaşım, controller seviyesinde if bloklarıyla yetki yazmak yerine, güvenlik politikasını deklaratif hale getirir.
Önemli tuzak: Method security ifadeleriyle erişilen bilgilerin null olma ihtimali ve exception yönetimi göz ardı edilirse, 403 yerine 500 görmek mümkündür. Bu yüzden güvenlik ifadeleri “mutlu yol” varsayımıyla değil, güvenli fall-back davranışlarıyla tasarlanmalıdır.

Yaygın tuzaklar ve pratik kontrol listesi
403/401 ayrımını doğru yapmak
401, kimliğin doğrulanamadığını (token yok, hatalı, süresi dolmuş) anlatır. 403 ise kimlik doğrulandı ama yetki yok demektir. Bu ayrım, istemci uygulamalarında doğru davranışı (yeniden giriş mi, yetki mesajı mı) tetikler. Hata yönetiminde bu ayrımı korumak, kullanıcı deneyimini ve gözlemlenebilirliği iyileştirir.
Token boyutu, loglar ve veri sızıntısı
JWT’ye gereğinden fazla claim koymak token’ı şişirir, ağ maliyetini artırır ve loglarda hassas verinin sızmasına sebep olabilir. Token içeriği base64 ile kodlansa da şifrelenmiş değildir; hassas veriler claim olarak taşınmamalıdır. Bu noktada minimum gerekli claim yaklaşımı güvenli bir çizgidir.
Kısa bir kontrol listesi
- Issuer (iss) ve audience (aud) doğrulaması net mi?
- Algoritma beklenen değerle sınırlandırıldı mı?
- Role/scope claim mapping açıkça tanımlandı mı?
- Token ömrü, refresh stratejisi ve iptal senaryosu düşünülmüş mü?
- CORS ayarları ortam bazında yönetiliyor mu?
- 401/403 ayrımı ve hata mesajları tutarlı mı?
Sonuç olarak, Spring Security ile JWT kurgusu kurarken en iyi yaklaşım “kolay çalıştırma” yerine doğru doğrulama, tutarlı yetkilendirme ve gözlemlenebilir hata yönetimi üçlüsünü birlikte ele almaktır. Bu sayede hem saldırı yüzeyi daralır hem de ekipler operasyonel sorunları daha hızlı teşhis eder.


