question: Is my Caddyfile and Google OAuth setup OK?
Hi,
I’m trying to protect sillytavern.jellystream.gr with Google OAuth 2.0 using the greenpau/caddy-security plugin.
What I want:
- Immediate redirect to Caddy portal + Google consent screen
- Access only for a small set of specific Google emails (all others blocked)
I’m not 100% sure if my Google OAuth setup is correct, though I have configured the Redirect URI exactly as:
https://sillytavern.jellystream.gr/oauth2/google/authorization-code-callback
Could you please:
- Review my Caddyfile snippet below and confirm if it looks right?
- Help me check if my OAuth setup might have any common issues?
Caddyfile snippet (emails redacted except mine):
{
order authenticate before respond
order authorize before respond
security {
oauth identity provider google {
realm google
driver google
client_id {env.GOOGLE_CLIENT_ID}.apps.googleusercontent.com
client_secret {env.GOOGLE_CLIENT_SECRET}
scopes openid email profile
}
authentication portal google_portal {
crypto default token lifetime 3600
crypto key sign-verify {env.JWT_SHARED_KEY}
enable identity provider google
transform user {
match realm google
exact match email redacted
action add role authp/admin
}
transform user {
match realm google
exact match email [email protected]
action add role authp/admin
}
transform user {
match realm google
exact match email redacted
action add role authp/admin
}
transform user {
match realm google
exact match email redacted
action add role authp/admin
}
transform user {
match realm google
block
}
}
authorization policy auth_policy {
set auth url https://sillytavern.jellystream.gr/oauth2/google/authorization-code-callback
allow roles authp/admin
}
}
}
sillytavern.jellystream.gr {
authorize with auth_policy
reverse_proxy localhost:8080
}
Latest relevant log (sensitive data redacted):
{
"level": "info",
"ts": 1748184015.392,
"logger": "http.log.access.log6",
"msg": "handled request",
"request": {
"remote_ip": "redacted",
"remote_port": "redacted",
"client_ip": "redacted",
"proto": "HTTP/2.0",
"method": "POST",
"host": "sillytavern.jellystream.gr",
"uri": "/api/settings/save",
"headers": {
"User-Agent": ["Mozilla/5.0 (Windows NT 10.0; Win64; x64)..."],
"Content-Type": ["application/json"],
...
"Origin": ["https://sillytavern.jellystream.gr"],
...
},
"tls": {
"resumed": false,
"version": 772,
"cipher_suite": 4865,
"proto": "h2",
"server_name": "sillytavern.jellystream.gr"
}
},
"bytes_read": 199519,
"user_id": "",
"duration": 0.040639,
"size": 15,
"status": 200,
"resp_headers": {
"Via": ["1.1 Caddy"],
"Strict-Transport-Security": ["max-age=15552000; includeSubDomains"],
...
"Content-Type": ["application/json; charset=utf-8"],
"Content-Length": ["15"],
"Date": ["Sun, 25 May 2025 14:40:15 GMT"]
}
}
Thanks for any guidance you can provide. I’m happy to provide additional info if needed.
What is responsible to serve set auth url https://sillytavern.jellystream.gr/oauth2/google/authorization-code-callback
I think you are missing “authenticate” directive
See this reference config https://github.com/greenpau/caddy-security/issues/353
Thanks—based on that issue you sent, I’ve revised my Caddyfile to this:
{
# ——— Added global ports so the security app can fully provision its internals ———
http_port 80
https_port 443
# ——— Pulled in the example’s extra ordering to avoid module conflicts ———
order trace before respond
order authenticate before respond
order authorize before basicauth
security {
oauth identity provider google {
realm google
driver google
client_id {env.GOOGLE_CLIENT_ID}.apps.googleusercontent.com
client_secret {env.GOOGLE_CLIENT_SECRET}
scopes openid email profile
}
authentication portal google_portal {
crypto default token lifetime 3600
crypto key sign-verify {env.JWT_SHARED_KEY}
enable identity provider google
# allow only these emails
transform user {
match realm google
exact match email redacted
action add role authp/admin
}
transform user {
match realm google
exact match email [email protected]
action add role authp/admin
}
transform user {
match realm google
exact match email redacted
action add role authp/admin
}
transform user {
match realm google
exact match email redacted
action add role authp/admin
}
transform user {
match realm google
block
}
}
authorization policy auth_policy {
set auth url https://sillytavern.jellystream.gr/oauth2/google/authorization-code-callback
allow roles authp/admin
}
}
}
sillytavern.jellystream.gr {
# ——— Added so Caddy terminates TLS on the callback URL without external certs ———
tls internal
# ——— Expose the plugin’s callback & login endpoints ———
route /oauth2/google/* {
authenticate with google_portal
}
# ——— Protect everything else: authenticate → authorize → proxy ———
route /* {
authenticate with google_portal
authorize with auth_policy
reverse_proxy localhost:8080
}
}
When I run ./caddy run --config CaddyfileT, I immediately get this panic before ever seeing a login screen:
2025/05/26 07:07:17.276 INFO security provisioning app instance {"app": "security"}
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x18 pc=0x170b425]
goroutine 1 [running]:
github.com/greenpau/go-authcrunch.(*Config).Validate(0x0)
github.com/greenpau/[email protected]/config.go:115 +0x25
github.com/greenpau/go-authcrunch.NewServer(0x0, ...)
I’ve never even reached the Google login screen. Can you help me understand:
- What’s still missing or mis‑configured so that
go-authcrunch.Configis nil? - Why the
authentication portal google_portalblock isn’t being provisioned?
Thanks in advance!
What is responsible to serve set auth url https://sillytavern.jellystream.gr/oauth2/google/authorization-code-callback
I think you are missing “authenticate” directive
I am not sure what to answer you. I essentially tried to duct tape the code together. So I have no clue, I assumed the plugin does it. Am I mistaken? Does the running server need to serve it?
This is wrong.
route /oauth2/google/* {
authenticate with google_portal
}
# ——— Protect everything else: authenticate → authorize → proxy ———
route /* {
authenticate with google_portal
authorize with auth_policy
reverse_proxy localhost:8080
}
It should be more like
route /auth* {
authenticate with google_portal
}
# ——— Protect everything else: authenticate → authorize → proxy ———
route /* {
authorize with auth_policy
reverse_proxy localhost:8080
}
Thanks for the reply! I am getting this now. Sorry for bothering so much with this, I just can't figure it out
PS C:\Caddy2> ./caddy run --config CaddyfileT 2025/05/26 16:00:57.545 INFO maxprocs: Leaving GOMAXPROCS=16: CPU quota undefined 2025/05/26 16:00:57.545 INFO GOMEMLIMIT is updated {"package": "github.com/KimMachineGun/automemlimit/memlimit", "GOMEMLIMIT": 46313935257, "previous": 9223372036854775807} 2025/05/26 16:00:57.554 INFO using config from file {"file": "CaddyfileT"} 2025/05/26 16:00:57.556 INFO adapted config to JSON {"adapter": "caddyfile"} 2025/05/26 16:00:57.565 INFO admin admin endpoint started {"address": "localhost:2019", "enforce_origin": false, "origins": ["//127.0.0.1:2019", "//localhost:2019", "//[::1]:2019"]} 2025/05/26 16:00:57.565 INFO tls.cache.maintenance started background certificate maintenance {"cache": "0xc00136a400"} 2025/05/26 16:00:57.566 INFO http.auto_https server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS {"server_name": "srv0", "https_port": 443} 2025/05/26 16:00:57.566 INFO http.auto_https enabling automatic HTTP->HTTPS redirects {"server_name": "srv0"} 2025/05/26 16:00:57.566 INFO security provisioning app instance {"app": "security"} 2025/05/26 16:00:57.566 INFO maxprocs: No GOMAXPROCS change to reset panic: runtime error: invalid memory address or nil pointer dereference [signal 0xc0000005 code=0x0 addr=0x18 pc=0x1edb425]
goroutine 1 [running]: github.com/greenpau/go-authcrunch.(*Config).Validate(0x0) github.com/greenpau/[email protected]/config.go:115 +0x25 github.com/greenpau/go-authcrunch.NewServer(0x0, 0xc00136b880) github.com/greenpau/[email protected]/server.go:69 +0x32 github.com/greenpau/caddy-security.(*App).Provision(0xc0013689c0, {{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc00136b780, 0x6, 0x8}, {0x0, 0x0, ...}, ...}) github.com/greenpau/[email protected]/app.go:91 +0x5ae github.com/caddyserver/caddy/v2.Context.LoadModuleByID({{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc00136b780, 0x6, 0x8}, {0x0, 0x0, 0x0}, ...}, ...) github.com/caddyserver/caddy/[email protected]/context.go:410 +0x755 github.com/caddyserver/caddy/v2.Context.App({{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc00136b780, 0x5, 0x8}, {0x0, 0x0, 0x0}, ...}, ...) github.com/caddyserver/caddy/[email protected]/context.go:494 +0xee github.com/greenpau/caddy-security.(*AuthnMiddleware).Provision(0xc00138eae0, {{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc00136b780, 0x5, 0x8}, {0x0, 0x0, ...}, ...}) github.com/greenpau/[email protected]/plugin_authn.go:56 +0x65 github.com/caddyserver/caddy/v2.Context.LoadModuleByID({{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc00136b780, 0x5, 0x8}, {0x0, 0x0, 0x0}, ...}, ...) github.com/caddyserver/caddy/[email protected]/context.go:410 +0x755 github.com/caddyserver/caddy/v2.Context.loadModuleInline({{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc0002c0400, 0x4, 0x4}, {0x0, 0x0, 0x0}, ...}, ...) github.com/caddyserver/caddy/[email protected]/context.go:468 +0xf0 github.com/caddyserver/caddy/v2.Context.LoadModule({{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc0002c0400, 0x4, 0x4}, {0x0, 0x0, 0x0}, ...}, ...) github.com/caddyserver/caddy/[email protected]/context.go:222 +0x6e6 github.com/caddyserver/caddy/v2/modules/caddyhttp.(*Route).ProvisionHandlers(0xc00137aa20, {{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc0002c0400, 0x4, 0x4}, {0x0, 0x0, ...}, ...}, ...)
github.com/caddyserver/caddy/[email protected]/modules/caddyhttp/routes.go:154 +0x6e github.com/caddyserver/caddy/v2/modules/caddyhttp.RouteList.ProvisionHandlers({0xc00137aa20, 0x1, 0xc0013922f0?}, {{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc0002c0400, 0x4, 0x4}, ...}, ...) github.com/caddyserver/caddy/[email protected]/modules/caddyhttp/routes.go:212 +0xa6 github.com/caddyserver/caddy/v2/modules/caddyhttp.RouteList.Provision({0xc00137aa20, 0x1, 0x1}, {{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc0002c0400, 0x4, 0x4}, ...}) github.com/caddyserver/caddy/[email protected]/modules/caddyhttp/routes.go:189 +0xb2 github.com/caddyserver/caddy/v2/modules/caddyhttp.(*Subroute).Provision(0xc0002bb340, {{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc0002c0400, 0x4, 0x4}, {0x0, 0x0, ...}, ...}) github.com/caddyserver/caddy/[email protected]/modules/caddyhttp/subroute.go:58 +0x5f github.com/caddyserver/caddy/v2.Context.LoadModuleByID({{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc0002c0400, 0x4, 0x4}, {0x0, 0x0, 0x0}, ...}, ...) github.com/caddyserver/caddy/[email protected]/context.go:410 +0x755 github.com/caddyserver/caddy/v2.Context.loadModuleInline({{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc0002c0400, 0x3, 0x4}, {0x0, 0x0, 0x0}, ...}, ...) github.com/caddyserver/caddy/[email protected]/context.go:468 +0xf0 github.com/caddyserver/caddy/v2.Context.LoadModule({{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc0002c0400, 0x3, 0x4}, {0x0, 0x0, 0x0}, ...}, ...) github.com/caddyserver/caddy/[email protected]/context.go:222 +0x6e6 github.com/caddyserver/caddy/v2/modules/caddyhttp.(*Route).ProvisionHandlers(0xc00137a900, {{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc0002c0400, 0x3, 0x4}, {0x0, 0x0, ...}, ...}, ...)
github.com/caddyserver/caddy/[email protected]/modules/caddyhttp/routes.go:154 +0x6e github.com/caddyserver/caddy/v2/modules/caddyhttp.RouteList.ProvisionHandlers({0xc00137a900, 0x1, 0x40?}, {{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc0002c0400, 0x3, 0x4}, ...}, ...)
github.com/caddyserver/caddy/[email protected]/modules/caddyhttp/routes.go:212 +0xa6 github.com/caddyserver/caddy/v2/modules/caddyhttp.RouteList.Provision({0xc00137a900, 0x1, 0x1}, {{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc0002c0400, 0x3, 0x4}, ...}) github.com/caddyserver/caddy/[email protected]/modules/caddyhttp/routes.go:189 +0xb2 github.com/caddyserver/caddy/v2/modules/caddyhttp.(*Subroute).Provision(0xc0002bb2c0, {{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc0002c0400, 0x3, 0x4}, {0x0, 0x0, ...}, ...}) github.com/caddyserver/caddy/[email protected]/modules/caddyhttp/subroute.go:58 +0x5f github.com/caddyserver/caddy/v2.Context.LoadModuleByID({{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc0002c0400, 0x3, 0x4}, {0x0, 0x0, 0x0}, ...}, ...) github.com/caddyserver/caddy/[email protected]/context.go:410 +0x755 github.com/caddyserver/caddy/v2.Context.loadModuleInline({{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc0002bb240, 0x2, 0x2}, {0x0, 0x0, 0x0}, ...}, ...) github.com/caddyserver/caddy/[email protected]/context.go:468 +0xf0 github.com/caddyserver/caddy/v2.Context.LoadModule({{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc0002bb240, 0x2, 0x2}, {0x0, 0x0, 0x0}, ...}, ...) github.com/caddyserver/caddy/[email protected]/context.go:222 +0x6e6 github.com/caddyserver/caddy/v2/modules/caddyhttp.(*Route).ProvisionHandlers(0xc00138d440, {{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc0002bb240, 0x2, 0x2}, {0x0, 0x0, ...}, ...}, ...)
github.com/caddyserver/caddy/[email protected]/modules/caddyhttp/routes.go:154 +0x6e github.com/caddyserver/caddy/v2/modules/caddyhttp.RouteList.ProvisionHandlers({0xc00138d440, 0x2, 0x1fe4487?}, {{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc0002bb240, 0x2, 0x2}, ...}, ...) github.com/caddyserver/caddy/[email protected]/modules/caddyhttp/routes.go:212 +0xa6 github.com/caddyserver/caddy/v2/modules/caddyhttp.RouteList.Provision({0xc00138d440, 0x2, 0x2}, {{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc0002bb240, 0x2, 0x2}, ...}) github.com/caddyserver/caddy/[email protected]/modules/caddyhttp/routes.go:189 +0xb2 github.com/caddyserver/caddy/v2/modules/caddyhttp.(*Subroute).Provision(0xc0002bb200, {{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc0002bb240, 0x2, 0x2}, {0x0, 0x0, ...}, ...}) github.com/caddyserver/caddy/[email protected]/modules/caddyhttp/subroute.go:58 +0x5f github.com/caddyserver/caddy/v2.Context.LoadModuleByID({{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc0002bb240, 0x2, 0x2}, {0x0, 0x0, 0x0}, ...}, ...) github.com/caddyserver/caddy/[email protected]/context.go:410 +0x755 github.com/caddyserver/caddy/v2.Context.loadModuleInline({{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc00135adb0, 0x1, 0x1}, {0x0, 0x0, 0x0}, ...}, ...) github.com/caddyserver/caddy/[email protected]/context.go:468 +0xf0 github.com/caddyserver/caddy/v2.Context.LoadModule({{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc00135adb0, 0x1, 0x1}, {0x0, 0x0, 0x0}, ...}, ...) github.com/caddyserver/caddy/[email protected]/context.go:222 +0x6e6 github.com/caddyserver/caddy/v2/modules/caddyhttp.(*Route).ProvisionHandlers(0xc001338a08, {{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc00135adb0, 0x1, 0x1}, {0x0, 0x0, ...}, ...}, ...)
github.com/caddyserver/caddy/[email protected]/modules/caddyhttp/routes.go:154 +0x6e github.com/caddyserver/caddy/v2/modules/caddyhttp.RouteList.ProvisionHandlers({0xc001338a08, 0x7, 0xc001366190?}, {{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc00135adb0, 0x1, 0x1}, ...}, ...) github.com/caddyserver/caddy/[email protected]/modules/caddyhttp/routes.go:212 +0xa6 github.com/caddyserver/caddy/v2/modules/caddyhttp.(*App).Provision(0xc0012146c0, {{0x36bdde8, 0xc00137fdd0}, 0xc001341740, 0xc0011fcc40, {0xc00135adb0, 0x1, 0x1}, {0x0, 0x0, ...}, ...}) github.com/caddyserver/caddy/[email protected]/modules/caddyhttp/app.go:367 +0xf09 github.com/caddyserver/caddy/v2.Context.LoadModuleByID({{0x36bde20, 0xc00134c410}, 0xc001341740, 0xc0011fcc40, {0xc00135adb0, 0x1, 0x1}, {0x0, 0x0, 0x0}, ...}, ...) github.com/caddyserver/caddy/[email protected]/context.go:410 +0x755 github.com/caddyserver/caddy/v2.Context.App({{0x36bde20, 0xc00134c410}, 0xc001341740, 0xc0011fcc40, {0x0, 0x0, 0x0}, {0x0, 0x0, 0x0}, ...}, ...) github.com/caddyserver/caddy/[email protected]/context.go:494 +0xee github.com/caddyserver/caddy/v2.provisionContext.func3(...) github.com/caddyserver/caddy/[email protected]/caddy.go:550 github.com/caddyserver/caddy/v2.provisionContext(0x0?, 0x1) github.com/caddyserver/caddy/[email protected]/caddy.go:555 +0x5b8 github.com/caddyserver/caddy/v2.run(0xc000d1f6a8?, 0x1) github.com/caddyserver/caddy/[email protected]/caddy.go:401 +0x78 github.com/caddyserver/caddy/v2.unsyncedDecodeAndRun({0xc00133ad80, 0xd1d, 0xd80}, 0x1) github.com/caddyserver/caddy/[email protected]/caddy.go:344 +0x145 github.com/caddyserver/caddy/v2.changeConfig({0x2400915, 0x4}, {0x2407ac6, 0x7}, {0xc00133a000, 0xd1d, 0xd80}, {0x0, 0x0}, 0x1) github.com/caddyserver/caddy/[email protected]/caddy.go:235 +0x6b9 github.com/caddyserver/caddy/v2.Load({0xc00133a000?, 0xa?, 0x0?}, 0x0?) github.com/caddyserver/caddy/[email protected]/caddy.go:134 +0x114 github.com/caddyserver/caddy/v2/cmd.cmdRun({0x0?}) github.com/caddyserver/caddy/[email protected]/cmd/commandfuncs.go:239 +0x80d github.com/caddyserver/caddy/v2/cmd.init.1.func2.WrapCommandFuncForCobra.1(0xc00029d808, {0x2400985?, 0x4?, 0x2400945?}) github.com/caddyserver/caddy/[email protected]/cmd/cobra.go:141 +0x2f github.com/spf13/cobra.(*Command).execute(0xc00029d808, {0xc0000adda0, 0x2, 0x2}) github.com/spf13/[email protected]/command.go:1015 +0xaaa github.com/spf13/cobra.(*Command).ExecuteC(0xc00029d208) github.com/spf13/[email protected]/command.go:1148 +0x46f github.com/spf13/cobra.(*Command).Execute(...) github.com/spf13/[email protected]/command.go:1071 github.com/caddyserver/caddy/v2/cmd.Main() github.com/caddyserver/caddy/[email protected]/cmd/main.go:72 +0x65 main.main() caddy/main.go:13 +0xf PS C:\Caddy2>
What is your current conf?
Sorry my internet droped out my current script is this
import snippets/common.caddy {
# # ——— Added global ports so the security app can fully provision its internals ———
# http_port 80
# https_port 443
# ——— Pulled in the example’s extra ordering to avoid module conflicts ———
order trace before respond
order authenticate before respond
order authorize before basicauth
security {
oauth identity provider google {
realm google
driver google
client_id {env.GOOGLE_CLIENT_ID}.apps.googleusercontent.com
client_secret {env.GOOGLE_CLIENT_SECRET}
scopes openid email profile
}
authentication portal google_portal {
crypto default token lifetime 3600
crypto key sign-verify {env.JWT_SHARED_KEY}
enable identity provider google
# allow only these emails
transform user {
match realm google
exact match email [email protected]
action add role authp/admin
}
}
authorization policy auth_policy {
set auth url https://sillytavern.jellystream.gr/oauth2/google/authorization-code-callback
allow roles authp/admin
}
}
}
sillytavern.jellystream.gr {
# ——— Added so Caddy terminates TLS on the callback URL without external certs ———
tls internal
# ——— Expose the plugin’s callback & login endpoints ———
route /auth* {
authenticate with google_portal
}
# ——— Protect everything else: authenticate → authorize → proxy ———
route /* {
authorize with auth_policy
reverse_proxy localhost:8080
}
}
I would also like to ask if I want more than one permitted mail what is the best way to do so?
@NullEqualsZero , try modifying auth url and adding matching key in authorization policy
authorization policy auth_policy {
set auth url https://sillytavern.jellystream.gr/auth/oauth2/google/authorization-code-callback
allow roles authp/admin
crypto key sign-verify {env.JWT_SHARED_KEY}
}
See if that works.
Thanks for the reply. I’ve made progress, and I now understand where things were going wrong.
Originally, I had import snippets/common.caddy at the top of my Caddyfile, which unintentionally turned the tls config into the global block. As a result, when the security block was defined later, it was not part of the global scope, which led to a cascade of parsing errors. Moving the global directives (including security) above any import statements fixed that issue — thanks for pointing me in the right direction there.
That said, I still have a few questions about how this plugin is supposed to work.
1. Redirect Flow / Splash Screen
Right now, after login, I get redirected to what I think is called the “splash screen” — a UI with a button labeled “SillyTavern.” Clicking the button doesn’t actually do anything, and I’d rather skip this screen entirely.
Ideally, after a successful Google login, the user should be sent directly to:
https://sillytavern.jellystream.gr/
My intention is to restrict access to just this subdomain (for now), so I want the login flow to be minimal. Is the post_auth_redirect directive the right way to achieve that?
2. Cookie Domain
In the official example, there's this line:
cookie domain myfiosgateway.com
In my case, should it be:
cookie domain sillytavern.jellystream.gr
Or could I leave it out entirely since I’m only protecting a single subdomain? If I later want to protect more subdomains (like somethingelse.jellystream.gr), should I change the cookie domain to .jellystream.gr so it works across all of them?
3. transform user block
Right now, I’m using this:
transform user {
match realm google
exact match email [email protected]
action add role authp/admin
}
Is this the correct way to only allow a specific Gmail address? Or is there a better way to both assign a role and deny access to all other users?
4. auth redirect URL confusion
In your examples, the auth url sometimes points to a dedicated subdomain like auth.example.com. Is this necessary, or can everything live under a single subdomain like I have now? Also, is it possible to support multiple providers (e.g. Google and GitHub) on the same domain with different routes?
Here’s my current working config for reference:
{
order authenticate before respond
order authorize before basicauth
security {
oauth identity provider google {
realm google
driver google
client_id {env.GOOGLE_CLIENT_ID}.apps.googleusercontent.com
client_secret {env.GOOGLE_CLIENT_SECRET}
scopes openid email profile
}
authentication portal google_portal {
crypto default token lifetime 3600
crypto key sign-verify {env.JWT_SHARED_KEY}
enable identity provider google
post_auth_redirect https://sillytavern.jellystream.gr/
transform user {
match realm google
exact match email [email protected]
action add role authp/admin
}
}
authorization policy auth_policy {
set auth url https://sillytavern.jellystream.gr/oauth2/google
allow roles authp/admin
crypto key sign-verify {env.JWT_SHARED_KEY}
}
}
}
import snippets/common.caddy
sillytavern.jellystream.gr {
import tls_cloudflare
route /auth/oauth2/google/* {
authenticate with google_portal
}
route /* {
authenticate with google_portal
authorize with auth_policy
reverse_proxy localhost:8081
}
log {
output file logs/sillytavern.log
}
}
Thanks again for all your help. I really appreciate the plugin and documentation — just trying to make sure I fully understand how it all works!