fix(api): CORS for connectRPC and grpc-web (#10227)

# Which Problems Are Solved

The CORS handler for the new connectRPC handlers was missing, leading to
unhandled preflight requests and a unusable api for browser based calls,
e.g. cross domain gRPC-web requests.

# How the Problems Are Solved

- Added the http CORS middleware to the connectRPC handlers.
- Added `Grpc-Timeout`, `Connect-Protocol-Version`,`Connect-Timeout-Ms`
to the default allowed headers (this improves also the old grpc-web
handling)
- Added `Grpc-Status`, `Grpc-Message`, `Grpc-Status-Details-Bin` to the
default exposed headers (this improves also the old grpc-web handling)

# Additional Changes

None

# Additional Context

noticed internally while testing other issues
This commit is contained in:
Livio Spring 2025-07-11 05:55:01 -04:00 committed by GitHub
parent 8f61b24532
commit 1b01fc6c40
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 37 additions and 25 deletions

View File

@ -201,7 +201,7 @@ func (a *API) registerConnectServer(service server.ConnectServer) {
methodNames[i] = string(methods.Get(i).Name())
}
a.connectServices[prefix] = methodNames
a.RegisterHandlerPrefixes(handler, prefix)
a.RegisterHandlerPrefixes(http_mw.CORSInterceptor(handler), prefix)
}
// HandleFunc allows registering a [http.HandlerFunc] on an exact

View File

@ -10,30 +10,36 @@ import (
)
const (
Authorization = "authorization"
Accept = "accept"
AcceptLanguage = "accept-language"
CacheControl = "cache-control"
ContentType = "content-type"
ContentLength = "content-length"
ContentLocation = "content-location"
Expires = "expires"
Location = "location"
Origin = "origin"
Pragma = "pragma"
UserAgentHeader = "user-agent"
ForwardedFor = "x-forwarded-for"
ForwardedHost = "x-forwarded-host"
ForwardedProto = "x-forwarded-proto"
Forwarded = "forwarded"
ZitadelForwarded = "x-zitadel-forwarded"
XUserAgent = "x-user-agent"
XGrpcWeb = "x-grpc-web"
XRequestedWith = "x-requested-with"
XRobotsTag = "x-robots-tag"
IfNoneMatch = "If-None-Match"
LastModified = "Last-Modified"
Etag = "Etag"
Authorization = "authorization"
Accept = "accept"
AcceptLanguage = "accept-language"
CacheControl = "cache-control"
ContentType = "content-type"
ContentLength = "content-length"
ContentLocation = "content-location"
Expires = "expires"
Location = "location"
Origin = "origin"
Pragma = "pragma"
UserAgentHeader = "user-agent"
ForwardedFor = "x-forwarded-for"
ForwardedHost = "x-forwarded-host"
ForwardedProto = "x-forwarded-proto"
Forwarded = "forwarded"
ZitadelForwarded = "x-zitadel-forwarded"
XUserAgent = "x-user-agent"
XGrpcWeb = "x-grpc-web"
XRequestedWith = "x-requested-with"
XRobotsTag = "x-robots-tag"
IfNoneMatch = "if-none-match"
LastModified = "last-modified"
Etag = "etag"
GRPCTimeout = "grpc-timeout"
ConnectProtocolVersion = "connect-protocol-version"
ConnectTimeoutMS = "connect-timeout-ms"
GrpcStatus = "grpc-status"
GrpcMessage = "grpc-message"
GrpcStatusDetailsBin = "grpc-status-details-bin"
ContentSecurityPolicy = "content-security-policy"
XXSSProtection = "x-xss-protection"

View File

@ -21,6 +21,9 @@ var (
http_utils.XUserAgent,
http_utils.XGrpcWeb,
http_utils.XRequestedWith,
http_utils.ConnectProtocolVersion,
http_utils.ConnectTimeoutMS,
http_utils.GRPCTimeout,
},
AllowedMethods: []string{
http.MethodOptions,
@ -34,6 +37,9 @@ var (
ExposedHeaders: []string{
http_utils.Location,
http_utils.ContentLength,
http_utils.GrpcStatus,
http_utils.GrpcMessage,
http_utils.GrpcStatusDetailsBin,
},
AllowOriginFunc: func(_ string) bool {
return true