diff --git a/.link-checker-service.toml b/.link-checker-service.toml
index de234f8..8eb3827 100644
--- a/.link-checker-service.toml
+++ b/.link-checker-service.toml
@@ -63,6 +63,9 @@ privKeyFile = "./dummy.priv.cer"
 pubKeyFile = "./public.cer"
 signingAlgorithm = "RS384"
 
+# alternatively, via JWKS
+# jwksUrl = "http://my-auth-provider/jwks"
+
 # searchForBodyPatterns allows searching for patterns in response bodies
 # enabling searchForBodyPatterns will impact checker performance
 # this feature is only configurable via the config file
diff --git a/CHANGES.md b/CHANGES.md
index 10120e5..41e34e3 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -2,6 +2,14 @@
 
 Notable changes will be documented here
 
+## 0.9.35
+
+- token validation via JWKS
+
+## 0.9.34
+
+- upgraded dependencies
+
 ## 0.9.33
 
 - Go v1.21
diff --git a/cmd/serve.go b/cmd/serve.go
index 7b49739..0431c54 100644
--- a/cmd/serve.go
+++ b/cmd/serve.go
@@ -25,6 +25,7 @@ const useJWTValidationKey = "useJWTValidation"
 const privKeyFileKey = "privKeyFile"
 const pubKeyFileKey = "pubKeyFile"
 const signingAlgorithmKey = "signingAlgorithm"
+const jwksUrlKey = "jwksUrl"
 const disableRequestLoggingKey = "disableRequestLogging"
 
 var serveCmd = &cobra.Command{
@@ -73,6 +74,7 @@ func fetchConfig() {
 
 func fetchJWTValidationConfig() {
 	jwtValidationOptions = &s.JWTValidationOptions{
+		JwksUrl:          viper.GetString(jwksUrlKey),
 		PrivKeyFile:      viper.GetString(privKeyFileKey),
 		PubKeyFile:       viper.GetString(pubKeyFileKey),
 		SigningAlgorithm: viper.GetString(signingAlgorithmKey),
@@ -104,6 +106,10 @@ func init() {
 		"Provide a valid public key to validate the JWT tokens against")
 	_ = viper.BindPFlag(signingAlgorithmKey, flags.Lookup(signingAlgorithmKey))
 
+	flags.String(jwksUrlKey, "",
+		"Provide a JWKS Url for automatic JWT validation automation")
+	_ = viper.BindPFlag(jwksUrlKey, flags.Lookup(jwksUrlKey))
+
 	flags.StringVar(&IPRateLimit, "IPRateLimit", "", "rate-limit requests from an IP. e.g. 5-S (5 per second), 1000-H (1000 per hour)")
 
 	serveCmd.PersistentFlags().BoolP(disableRequestLoggingKey, "s", false, "disable request logging")
diff --git a/go.mod b/go.mod
index 7fd6c00..2492fc4 100644
--- a/go.mod
+++ b/go.mod
@@ -3,6 +3,7 @@ module github.com/siemens/link-checker-service
 go 1.19
 
 require (
+	github.com/MicahParks/keyfunc v1.9.0
 	github.com/appleboy/gin-jwt/v2 v2.9.1
 	github.com/darren/gpac v0.0.0-20210609082804-b56d6523a3af
 	github.com/dgraph-io/ristretto v0.1.1
@@ -10,7 +11,7 @@ require (
 	github.com/gin-gonic/gin v1.9.1
 	github.com/go-resty/resty/v2 v2.10.0
 	github.com/gobwas/glob v0.2.3
-	github.com/golang-jwt/jwt v3.2.2+incompatible
+	github.com/golang-jwt/jwt/v4 v4.5.0
 	github.com/google/uuid v1.5.0
 	github.com/mitchellh/go-homedir v1.1.0
 	github.com/patrickmn/go-cache v2.1.0+incompatible
@@ -39,7 +40,6 @@ require (
 	github.com/go-playground/validator/v10 v10.16.0 // indirect
 	github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
 	github.com/goccy/go-json v0.10.2 // indirect
-	github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
 	github.com/golang/glog v1.2.0 // indirect
 	github.com/google/pprof v0.0.0-20231212022811-ec68065c825e // indirect
 	github.com/hashicorp/hcl v1.0.0 // indirect
@@ -50,7 +50,6 @@ require (
 	github.com/magiconair/properties v1.8.7 // indirect
 	github.com/mattn/go-isatty v0.0.20 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
-	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
 	github.com/pelletier/go-toml/v2 v2.1.1 // indirect
 	github.com/pkg/errors v0.9.1 // indirect
diff --git a/go.sum b/go.sum
index ca1a771..5e0516f 100644
--- a/go.sum
+++ b/go.sum
@@ -2,6 +2,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
 cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/DataDog/datadog-go/v5 v5.0.2/go.mod h1:ZI9JFB4ewXbw1sBnF4sxsR2k1H3xjV+PUAOUsHvKpcU=
+github.com/MicahParks/keyfunc v1.9.0 h1:lhKd5xrFHLNOWrDc4Tyb/Q1AJ4LCzQ48GVJyVIID3+o=
+github.com/MicahParks/keyfunc v1.9.0/go.mod h1:IdnCilugA0O/99dW+/MkvlyrsX8+L8+x95xuVNtM5jw=
 github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
 github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
 github.com/appleboy/gin-jwt/v2 v2.9.1 h1:l29et8iLW6omcHltsOP6LLk4s3v4g2FbFs0koxGWVZs=
@@ -99,8 +101,7 @@ github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGF
 github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
 github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
 github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
-github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
-github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
+github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
 github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
 github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
 github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
@@ -169,7 +170,6 @@ github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk
 github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
 github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
diff --git a/main_test_support.go b/main_test_support.go
index 1945b6a..5c3b105 100644
--- a/main_test_support.go
+++ b/main_test_support.go
@@ -18,7 +18,7 @@ import (
 	"os"
 	"time"
 
-	"github.com/golang-jwt/jwt"
+	"github.com/golang-jwt/jwt/v4"
 )
 
 // adapted the testing technique from
diff --git a/server/server.go b/server/server.go
index ff51aa2..5acfc1b 100644
--- a/server/server.go
+++ b/server/server.go
@@ -8,6 +8,8 @@ package server
 
 import (
 	"context"
+	"github.com/gin-contrib/cors"
+	"github.com/gobwas/glob"
 	"io"
 	"log"
 	"math"
@@ -17,14 +19,13 @@ import (
 	"sync"
 	"time"
 
-	jwt "github.com/appleboy/gin-jwt/v2"
-	"github.com/gobwas/glob"
+	"github.com/MicahParks/keyfunc"
+	ginGwt "github.com/appleboy/gin-jwt/v2"
+	jwtv4 "github.com/golang-jwt/jwt/v4"
 	"github.com/ulule/limiter/v3"
 	gm "github.com/ulule/limiter/v3/drivers/middleware/gin"
 	"github.com/ulule/limiter/v3/drivers/store/memory"
 
-	"github.com/gin-contrib/cors"
-
 	"github.com/gin-gonic/gin"
 	"github.com/siemens/link-checker-service/infrastructure"
 )
@@ -39,6 +40,7 @@ type JWTValidationOptions struct {
 	PrivKeyFile      string
 	PubKeyFile       string
 	SigningAlgorithm string
+	JwksUrl          string
 }
 
 // Options configures the web service instance
@@ -141,8 +143,7 @@ func (s *Server) setupRoutes() {
 	s.setUpRateLimiting(checkURLsRoutes)
 
 	if s.options.JWTValidationOptions != nil {
-		s.setUpJWTValidation(checkURLsRoutes)
-		s.setUpJWTValidation(statsRoutes)
+		s.setUpJWTValidation(checkURLsRoutes, statsRoutes)
 	}
 
 	checkURLsRoutes.POST("", s.checkURLs)
@@ -374,7 +375,7 @@ func (s *Server) isBlacklisted(input URLRequest) bool {
 	return false
 }
 
-func (s *Server) setUpJWTValidation(routerGroup *gin.RouterGroup) {
+func (s *Server) setUpJWTValidation(routerGroups ...*gin.RouterGroup) {
 	if s.options.JWTValidationOptions == nil {
 		log.Fatal("JWT Validation not set up correctly")
 	}
@@ -385,7 +386,8 @@ func (s *Server) setUpJWTValidation(routerGroup *gin.RouterGroup) {
 	log.Printf("  SigningAlgorithm: %v", s.options.JWTValidationOptions.SigningAlgorithm)
 
 	// the jwt middleware
-	middleware, err := jwt.New(&jwt.GinJWTMiddleware{
+	middleware, err := ginGwt.New(&ginGwt.GinJWTMiddleware{
+		KeyFunc:          tryGetJwksKeyFunc(s.options.JWTValidationOptions.JwksUrl),
 		PrivKeyFile:      s.options.JWTValidationOptions.PrivKeyFile,
 		PubKeyFile:       s.options.JWTValidationOptions.PubKeyFile,
 		SigningAlgorithm: s.options.JWTValidationOptions.SigningAlgorithm,
@@ -399,7 +401,21 @@ func (s *Server) setUpJWTValidation(routerGroup *gin.RouterGroup) {
 		log.Fatal("JWT Error:" + err.Error())
 	}
 
-	routerGroup.Use(middleware.MiddlewareFunc())
+	for _, routerGroup := range routerGroups {
+		routerGroup.Use(middleware.MiddlewareFunc())
+	}
+}
+
+func tryGetJwksKeyFunc(jwksURL string) func(token *jwtv4.Token) (interface{}, error) {
+	kf, err := keyfunc.Get(jwksURL, keyfunc.Options{
+		// to do: configurable
+		RefreshInterval: 1 * time.Hour,
+	})
+	if err != nil {
+		return nil
+	}
+	log.Printf("JWKS configured with the url: %s", jwksURL)
+	return kf.Keyfunc
 }
 
 func (s *Server) setUpRateLimiting(routerGroup *gin.RouterGroup) {