caddy-security icon indicating copy to clipboard operation
caddy-security copied to clipboard

question: Is my Caddyfile and Google OAuth setup OK?

Open NullEqualsZero opened this issue 7 months ago • 10 comments

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:

  1. Review my Caddyfile snippet below and confirm if it looks right?
  2. 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.

NullEqualsZero avatar May 25 '25 14:05 NullEqualsZero

What is responsible to serve set auth url https://sillytavern.jellystream.gr/oauth2/google/authorization-code-callback

I think you are missing “authenticate” directive

greenpau avatar May 25 '25 19:05 greenpau

See this reference config https://github.com/greenpau/caddy-security/issues/353

greenpau avatar May 25 '25 19:05 greenpau

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:

  1. What’s still missing or mis‑configured so that go-authcrunch.Config is nil?
  2. Why the authentication portal google_portal block isn’t being provisioned?

Thanks in advance!

NullEqualsZero avatar May 26 '25 07:05 NullEqualsZero

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?

NullEqualsZero avatar May 26 '25 07:05 NullEqualsZero

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
  }

greenpau avatar May 26 '25 15:05 greenpau

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>

NullEqualsZero avatar May 26 '25 16:05 NullEqualsZero

What is your current conf?

greenpau avatar May 26 '25 17:05 greenpau

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 avatar May 27 '25 06:05 NullEqualsZero

@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.

greenpau avatar May 27 '25 11:05 greenpau

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!

NullEqualsZero avatar May 27 '25 15:05 NullEqualsZero