Serve Access Gate denied HTML as 200 for iframe display.

AppAPI sets frame-ancestors none on 403 proxy responses, which blanked the ExApp iframe; keep API denials as 403.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Konrad Neitzel
2026-08-27 18:43:01 +02:00
co-authored by Cursor
parent 92d8efea47
commit 69af4d19c8
2 changed files with 18 additions and 4 deletions
+17 -3
View File
@@ -177,8 +177,10 @@ func (g AccessGate) normalized() *AccessGate {
func (g *AccessGate) writeDenied(w http.ResponseWriter, r *http.Request) {
if acceptsHTML(r.Header.Get("Accept")) {
// 200 so AppAPI's proxy CSP keeps frame-ancestors 'self' and the ExApp
// iframe can show the message (403 responses get frame-ancestors 'none').
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(http.StatusForbidden)
w.WriteHeader(http.StatusOK)
_, _ = w.Write(deniedHTML)
return
}
@@ -216,7 +218,19 @@ var defaultSkipPaths = []string{"/heartbeat", "/enabled", "/init"}
var deniedHTML = []byte(`<!DOCTYPE html>
<html lang="en">
<head><meta charset="utf-8"><title>Access denied</title></head>
<body><h1>Access denied</h1><p>You are not a member of a required group for this app.</p></body>
<head>
<meta charset="utf-8">
<title>Access denied</title>
<style>
:root { font-family: ui-sans-serif, system-ui, sans-serif; color: #1a1a1a; }
body { margin: 2rem; max-width: 40rem; }
h1 { font-size: 1.4rem; margin-bottom: 0.5rem; }
p { color: #444; line-height: 1.5; }
</style>
</head>
<body>
<h1>Access denied</h1>
<p>You are not a member of a required group for this app. Ask an administrator to add you to the group if you need access.</p>
</body>
</html>
`)