deprecate authJWTInHTTPQuery and disable JWTs in query parameters (#5648)

This fixes a long standing security flaw. Even though it's a breaking
change, few users should be impacted since this feature has been discouraged
for some time.
This commit is contained in:
Alessandro Ros
2026-04-06 18:03:22 +02:00
committed by GitHub
parent 4472bcfc4b
commit 6d6ebee80d
5 changed files with 14 additions and 12 deletions
+4 -2
View File
@@ -270,6 +270,10 @@ components:
type: string
authJWTClaimKey:
type: string
authJWTInHTTPQuery:
type: boolean
nullable: true
deprecated: true
authJWTIssuer:
type: string
authJWTAudience:
@@ -278,8 +282,6 @@ components:
type: array
items:
$ref: '#/components/schemas/AuthInternalUserPermission'
authJWTInHTTPQuery:
type: boolean
# Control API
api:
+4 -3
View File
@@ -63,7 +63,7 @@ func matchesPermission(perms []conf.AuthInternalUserPermission, req *Request) bo
return false
}
func getToken(jwtInHTTPQuery bool, req *Request) (string, bool) {
func getToken(jwtInHTTPQuery *bool, req *Request) (string, bool) {
switch {
case req.Credentials.Token != "":
return req.Credentials.Token, true
@@ -72,7 +72,8 @@ func getToken(jwtInHTTPQuery bool, req *Request) (string, bool) {
return req.Credentials.Pass, true
// always allow passing tokens through query parameters with RTSP and RTMP since there's no alternative.
case req.Protocol == ProtocolRTSP || req.Protocol == ProtocolRTMP || (jwtInHTTPQuery && isHTTP(req)):
case req.Protocol == ProtocolRTSP || req.Protocol == ProtocolRTMP ||
(jwtInHTTPQuery != nil && *jwtInHTTPQuery && isHTTP(req)):
v, err := url.ParseQuery(req.Query)
if err == nil {
if len(v["token"]) == 1 {
@@ -100,7 +101,7 @@ type Manager struct {
JWTJWKSFingerprint string
JWTClaimKey string
JWTExclude []conf.AuthInternalUserPermission
JWTInHTTPQuery bool
JWTInHTTPQuery *bool
JWTIssuer string
JWTAudience string
ReadTimeout time.Duration
+5 -2
View File
@@ -268,7 +268,7 @@ type Conf struct {
AuthJWTJWKSFingerprint string `json:"authJWTJWKSFingerprint"`
AuthJWTClaimKey string `json:"authJWTClaimKey"`
AuthJWTExclude []AuthInternalUserPermission `json:"authJWTExclude"`
AuthJWTInHTTPQuery bool `json:"authJWTInHTTPQuery"`
AuthJWTInHTTPQuery *bool `json:"authJWTInHTTPQuery,omitempty" deprecated:"true"`
AuthJWTIssuer string `json:"authJWTIssuer"`
AuthJWTAudience string `json:"authJWTAudience"`
@@ -437,7 +437,6 @@ func (conf *Conf) setDefaults() {
},
}
conf.AuthJWTClaimKey = "mediamtx_permissions"
conf.AuthJWTInHTTPQuery = true
// Control API
conf.APIAddress = ":9997"
@@ -727,6 +726,10 @@ func (conf *Conf) Validate(l logger.Writer) error {
}
}
if conf.AuthJWTInHTTPQuery != nil {
l.Log(logger.Warn, "parameter 'authJWTInHTTPQuery' is deprecated and will be removed in a future release")
}
// Control API (deprecated params)
if conf.APIAllowOrigin != nil {
+1 -1
View File
@@ -739,7 +739,7 @@ func (p *Core) closeResources(newConf *conf.Conf, calledByAPI bool) {
newConf.AuthJWTJWKSFingerprint != p.conf.AuthJWTJWKSFingerprint ||
newConf.AuthJWTClaimKey != p.conf.AuthJWTClaimKey ||
!reflect.DeepEqual(newConf.AuthJWTExclude, p.conf.AuthJWTExclude) ||
newConf.AuthJWTInHTTPQuery != p.conf.AuthJWTInHTTPQuery ||
!reflect.DeepEqual(newConf.AuthJWTInHTTPQuery, p.conf.AuthJWTInHTTPQuery) ||
newConf.AuthJWTIssuer != p.conf.AuthJWTIssuer ||
newConf.AuthJWTAudience != p.conf.AuthJWTAudience ||
newConf.ReadTimeout != p.conf.ReadTimeout
-4
View File
@@ -149,10 +149,6 @@ authJWTClaimKey: mediamtx_permissions
# Actions to exclude from JWT-based authentication.
# Format is the same as the one of user permissions.
authJWTExclude: []
# Allow passing the JWT through query parameters of HTTP requests (i.e. ?token=JWT).
# This is a security risk and will be disabled in the future.
# RTSP and RTMP always allow JWT in query even if disabled, since there is no alternative.
authJWTInHTTPQuery: true
# Expected issuer (iss) claim in the JWT. Leave empty to skip validation.
authJWTIssuer:
# Expected audience (aud) claim in the JWT. Leave empty to skip validation.