Repository: goauthentik/authentik

Issue:
Proxy provider incorrect redirect behaviour
**Describe the bug**
This bug manifests as a seemingly random-ish redirect after a page refresh when the proxy token has expired and the user is redirected back to the app from the proxy outpost that has just generated a new token.

To make it more clear - let's say we have a forward auth single application set up correctly and working - let's call the application The Echo Server: `https://echo.domain.tld`. We visit the Echo Server, idle for some time, and manage to wait enough so that the proxy token expires. When the Echo Servers sends a request to some kind of Echo Server's **resource (`https://echo.domain.tld/static/resource.json`)** AFTER the token expires (which fails because of the expired token) and THEN we refresh the current page (`https://echo.domain.tld/home`), we get redirected to authentik proxy outpost which in turns generates a new token and redirects the user back to the Echo Server - but when authentik eventually redirects the user back to the app the URL is **`https://echo.domain.tld/static/resource.json`** and not the original path from which the flow started `https://echo.domain.tld/home`.


**To Reproduce**
Steps to reproduce the behavior:

1. Have a working setup of a protected application with a proxy provider in Forward auth (single application) mode ("The Echo Server" described above)
2. In the app's proxy provider update the Token validity setting to a short duration, e.g. `seconds=30` for demonstration purposes
3. Go to the app (e.g. `https://echo.domain.tld/home`) and successfully authenticate/authorize.
4. Wait 30 seconds until the token expires
5. Open a developer console and simulate an artificial resource request of some kind: `fetch("https://echo.domain.tld/static/resource.json")` - the fetch fails because the token has expired. You can verify in the network tab that the fetch request gets redirected to the outpost and fails: `https://echo.domain.tld/outpost.goauthentik.io/start?rd=https%3A%2F%2Fecho.domain.tld%2Fstatic%2Fresource.json`.
6. Now refresh the page while still being at the same URL: `https://echo.domain.tld/home` - You can verify in the network tab that the refresh request gets redirected to the outpost _with correct redirect argument set_: `https://echo.domain.tld/outpost.goauthentik.io/start?rd=https%3A%2F%2Fecho.domain.tld%2Fhome`
7. You eventually get redirected back to the app's resource requested in step 5: `https://echo.domain.tld/static/resource.json`

**Expected behavior**
I would expect to be eventually redirected back to the `https://echo.domain.tld/home` page.

**Logs**

<details>
<summary>Logs</summary>

```
{"event":"/outpost.goauthentik.io/auth/nginx","host":"echo.domain.tld","level":"info","logger":"authentik.outpost.proxyv2.application","method":"GET","name":"Echo server proxy","remote":"xxx.xxx.xxx.xxx","runtime":"0.343","scheme":"http","size":0,"status":200,"timestamp":"2023-05-14T22:28:10Z","user":"UserName","user_agent":"USER_AGENT"}
{"event":"/outpost.goauthentik.io/auth/nginx","host":"echo.domain.tld","level":"info","logger":"authentik.outpost.proxyv2.application","method":"GET","name":"Echo server proxy","remote":"xxx.xxx.xxx.xxx","runtime":"0.930","scheme":"http","size":21,"status":401,"timestamp":"2023-05-14T22:29:07Z","user_agent":"USER_AGENT"}
{"event":"/outpost.goauthentik.io/start?rd=https%3A%2F%2Fecho.domain.tld%2Fstatic%2Fresource.json","host":"echo.domain.tld","level":"info","logger":"authentik.outpost.proxyv2.application","method":"GET","name":"Echo server proxy","remote":"xxx.xxx.xxx.xxx","runtime":"1.123","scheme":"http","size":359,"status":302,"timestamp":"2023-05-14T22:29:07Z","user_agent":"USER_AGENT"}
{"event":"/outpost.goauthentik.io/auth/nginx","host":"echo.domain.tld","level":"info","logger":"authentik.outpost.proxyv2.application","method":"GET","name":"Echo server proxy","remote":"xxx.xxx.xxx.xxx","runtime":"0.933","scheme":"http","size":21,"status":401,"timestamp":"2023-05-14T22:29:11Z","user_agent":"USER_AGENT"}
{"event":"/outpost.goauthentik.io/start?rd=https%3A%2F%2Fecho.domain.tld%2Fhome","host":"echo.domain.tld","level":"info","logger":"authentik.outpost.proxyv2.application","method":"GET","name":"Echo server proxy","remote":"xxx.xxx.xxx.xxx","runtime":"1.319","scheme":"http","size":359,"status":302,"timestamp":"2023-05-14T22:29:11Z","user_agent":"USER_AGENT"}
{"auth_via": "session", "event": "/application/o/authorize/?client_id=ffffffffffffffffffffffffffffffff&redirect_uri=https%3A%2F%2Fecho.domain.tld%2Foutpost.goauthentik.io%2Fcallback%3FX-authentik-auth-callback%3Dtrue&response_type=code&scope=openid+profile+email+ak_proxy&state=NdC1Ol7jMCT8oS_P9oKDQ3J6gvnETS4eWUbMbo4DbRo", "host": "auth.domain.tld", "level": "info", "logger": "authentik.asgi", "method": "GET", "pid": 24, "remote": "xxx.xxx.xxx.xxx", "request_id": "5b1ce3f63ab44b67ae482cd4eef3548d", "runtime": 74, "scheme": "https", "status": 302, "timestamp": "2023-05-14T22:29:11.311489", "user": "UserName", "user_agent": "USER_AGENT"}
{"auth_via": "session", "event": "/if/flow/default-provider-authorization-explicit-consent/?client_id=ffffffffffffffffffffffffffffffff&redirect_uri=https%3A%2F%2Fecho.domain.tld%2Foutpost.goauthentik.io%2Fcallback%3FX-authentik-auth-callback%3Dtrue&response_type=code&scope=openid+profile+email+ak_proxy&state=NdC1Ol7jMCT8oS_P9oKDQ3J6gvnETS4eWUbMbo4DbRo", "host": "auth.domain.tld", "level": "info", "logger": "authentik.asgi", "method": "GET", "pid": 24, "remote": "xxx.xxx.xxx.xxx", "request_id": "9dabf88c7f7f40cb909a317c47132181", "runtime": 33, "scheme": "https", "status": 200, "timestamp": "2023-05-14T22:29:11.362915", "user": "UserName", "user_agent": "USER_AGENT"}
{"event":"/static/dist/poly.js.map","host":"auth.domain.tld","level":"info","logger":"authentik.router","method":"GET","remote":"xxx.xxx.xxx.xxx","runtime":"4.872","scheme":"http","size":0,"status":304,"timestamp":"2023-05-14T22:29:11Z","user_agent":"USER_AGENT"}
{"event":"/static/dist/standalone/loading/vendor-320681c9.js.map","host":"auth.domain.tld","level":"info","logger":"authentik.router","method":"GET","remote":"xxx.xxx.xxx.xxx","runtime":"1.094","scheme":"http","size":0,"status":304,"timestamp":"2023-05-14T22:29:12Z","user_agent":"USER_AGENT"}
{"event":"/static/dist/standalone/loading/api-f65fd993.js.map","host":"auth.domain.tld","level":"info","logger":"authentik.router","method":"GET","remote":"xxx.xxx.xxx.xxx","runtime":"0.742","scheme":"http","size":0,"status":304,"timestamp":"2023-05-14T22:29:12Z","user_agent":"USER_AGENT"}
{"event":"/static/dist/standalone/loading/locale-en-f660cb3b.js.map","host":"auth.domain.tld","level":"info","logger":"authentik.router","method":"GET","remote":"xxx.xxx.xxx.xxx","runtime":"0.523","scheme":"http","size":0,"status":304,"timestamp":"2023-05-14T22:29:12Z","user_agent":"USER_AGENT"}
{"event":"/static/dist/standalone/loading/index.js.map","host":"auth.domain.tld","level":"info","logger":"authentik.router","method":"GET","remote":"xxx.xxx.xxx.xxx","runtime":"0.438","scheme":"http","size":53898,"status":200,"timestamp":"2023-05-14T22:29:12Z","user_agent":"USER_AGENT"}
{"event":"/static/dist/standalone/loading/index.js.map","host":"auth.domain.tld","level":"info","logger":"authentik.router","method":"GET","remote":"xxx.xxx.xxx.xxx","runtime":"0.196","scheme":"http","size":0,"status":304,"timestamp":"2023-05-14T22:29:12Z","user_agent":"USER_AGENT"}
{"event":"/static/dist/flow/FlowInterface-d33d9ac4.js.map","host":"auth.domain.tld","level":"info","logger":"authentik.router","method":"GET","remote":"xxx.xxx.xxx.xxx","runtime":"2.285","scheme":"http","size":0,"status":304,"timestamp":"2023-05-14T22:29:12Z","user_agent":"USER_AGENT"}
{"event":"/static/dist/flow/FlowInterface.js.map","host":"auth.domain.tld","level":"info","logger":"authentik.router","method":"GET","remote":"xxx.xxx.xxx.xxx","runtime":"0.127","scheme":"http","size":0,"status":304,"timestamp":"2023-05-14T22:29:12Z","user_agent":"USER_AGENT"}
{"event":"/static/dist/flow/locale-en-f660cb3b.js.map","host":"auth.domain.tld","level":"info","logger":"authentik.router","method":"GET","remote":"xxx.xxx.xxx.xxx","runtime":"1.856","scheme":"http","size":0,"status":304,"timestamp":"2023-05-14T22:29:12Z","user_agent":"USER_AGENT"}
{"event":"/static/dist/flow/vendor-cm-00a4719e.js.map","host":"auth.domain.tld","level":"info","logger":"authentik.router","method":"GET","remote":"xxx.xxx.xxx.xxx","runtime":"7.299","scheme":"http","size":0,"status":304,"timestamp":"2023-05-14T22:29:12Z","user_agent":"USER_AGENT"}
{"event":"/static/dist/flow/api-befd9628.js.map","host":"auth.domain.tld","level":"info","logger":"authentik.router","method":"GET","remote":"xxx.xxx.xxx.xxx","runtime":"13.889","scheme":"http","size":0,"status":304,"timestamp":"2023-05-14T22:29:12Z","user_agent":"USER_AGENT"}
{"event":"/static/dist/assets/icons/icon_left_brand.svg","host":"auth.domain.tld","level":"info","logger":"authentik.router","method":"GET","remote":"xxx.xxx.xxx.xxx","runtime":"0.511","scheme":"http","size":4861,"status":200,"timestamp":"2023-05-14T22:29:12Z","user_agent":"USER_AGENT"}
{"event":"/if/flow/default-provider-authorization-explicit-consent/assets/fonts/RedHatText/RedHatText-Regular.woff2","host":"auth.domain.tld","level":"info","logger":"authentik.router","method":"GET","remote":"xxx.xxx.xxx.xxx","runtime":"0.523","scheme":"http","size":3768,"status":200,"timestamp":"2023-05-14T22:29:12Z","user_agent":"USER_AGENT"}
{"event":"/if/flow/default-provider-authorization-explicit-consent/assets/fonts/RedHatDisplay/RedHatDisplay-Medium.woff2","host":"auth.domain.tld","level":"info","logger":"authentik.router","method":"GET","remote":"xxx.xxx.xxx.xxx","runtime":"0.521","scheme":"http","size":28661,"status":200,"timestamp":"2023-05-14T22:29:12Z","user_agent":"USER_AGENT"}
{"event":"/static/dist/flow/vendor-25865c6e.js.map","host":"auth.domain.tld","level":"info","logger":"authentik.router","method":"GET","remote":"xxx.xxx.xxx.xxx","runtime":"45.016","scheme":"http","size":0,"status":304,"timestamp":"2023-05-14T22:29:12Z","user_agent":"USER_AGENT"}
{"event":"/static/dist/flow/FlowInterface-d33d9ac4.js.map","host":"auth.domain.tld","level":"info","logger":"authentik.router","method":"GET","remote":"xxx.xxx.xxx.xxx","runtime":"1.530","scheme":"http","size":0,"status":304,"timestamp":"2023-05-14T22:29:12Z","user_agent":"USER_AGENT"}
{"auth_via": "session", "event": "/api/v3/flows/executor/default-provider-authorization-explicit-consent/?query=client_id%3Dffffffffffffffffffffffffffffffff%26redirect_uri%3Dhttps%253A%252F%252Fecho.domain.tld%252Foutpost.goauthentik.io%252Fcallback%253FX-authentik-auth-callback%253Dtrue%26response_type%3Dcode%26scope%3Dopenid%2Bprofile%2Bemail%2Bak_proxy%26state%3DNdC1Ol7jMCT8oS_P9oKDQ3J6gvnETS4eWUbMbo4DbRo", "host": "auth.domain.tld", "level": "info", "logger": "authentik.asgi", "method": "GET", "pid": 24, "remote": "xxx.xxx.xxx.xxx", "request_id": "bccf832ab85840c7899bef18fb76899e", "runtime": 233, "scheme": "https", "status": 302, "timestamp": "2023-05-14T22:29:12.466727", "user": "UserName", "user_agent": "USER_AGENT"}
{"action": "authorize_application", "auth_via": "session", "client_ip": "xxx.xxx.xxx.xxx", "context": {"authorized_application": {"app": "authentik_core", "model_name": "application", "name": "Echo server", "pk": "d208963c731d4cb282ae64397f731688"}, "flow": "a8c59e9e6fbc4e1d9a53365db1bf8704", "http_request": {"args": {"client_id": "ffffffffffffffffffffffffffffffff", "redirect_uri": "https://echo.domain.tld/outpost.goauthentik.io/callback?X-authentik-auth-callback=true", "response_type": "code", "scope": "openid profile email ak_proxy", "state": "NdC1Ol7jMCT8oS_P9oKDQ3J6gvnETS4eWUbMbo4DbRo"}, "method": "GET", "path": "/api/v3/flows/executor/default-provider-authorization-explicit-consent/"}, "scopes": "openid profile email ak_proxy"}, "event": "Created Event", "host": "auth.domain.tld", "level": "info", "logger": "authentik.events.models", "pid": 24, "request_id": "15975e5a84894e668b1127b804d7b3d8", "timestamp": "2023-05-14T22:29:12.654030", "user": {"email": "email@example.com", "pk": 12, "username": "UserName"}}
{"auth_via": "session", "event": "Task published", "host": "auth.domain.tld", "level": "info", "logger": "authentik.root.celery", "pid": 24, "request_id": "15975e5a84894e668b1127b804d7b3d8", "task_id": "94594c44-1672-4710-b659-96c22b3580f6", "task_name": "authentik.events.tasks.event_notification_handler", "timestamp": "2023-05-14T22:29:12.678197"}
{"auth_via": "session", "event": "/api/v3/flows/executor/default-provider-authorization-explicit-consent/?query=client_id%3Dffffffffffffffffffffffffffffffff%26redirect_uri%3Dhttps%253A%252F%252Fecho.domain.tld%252Foutpost.goauthentik.io%252Fcallback%253FX-authentik-auth-callback%253Dtrue%26response_type%3Dcode%26scope%3Dopenid%2Bprofile%2Bemail%2Bak_proxy%26state%3DNdC1Ol7jMCT8oS_P9oKDQ3J6gvnETS4eWUbMbo4DbRo", "host": "auth.domain.tld", "level": "info", "logger": "authentik.asgi", "method": "GET", "pid": 24, "remote": "xxx.xxx.xxx.xxx", "request_id": "15975e5a84894e668b1127b804d7b3d8", "runtime": 113, "scheme": "https", "status": 200, "timestamp": "2023-05-14T22:29:12.709587", "user": "UserName", "user_agent": "USER_AGENT"}
{"auth_via": "unauthenticated", "event": "/-/health/ready/", "host": "localhost:9000", "level": "info", "logger": "authentik.asgi", "method": "HEAD", "pid": 24, "remote": "127.0.0.1", "request_id": "5cc814939c734f85ab612559d77ee914", "runtime": 18, "scheme": "http", "status": 204, "timestamp": "2023-05-14T22:29:12.845074", "user": "", "user_agent": "goauthentik.io lifecycle Healthcheck"}
{"auth_via": "unauthenticated", "event": "/application/o/token/", "host": "auth.domain.tld", "level": "info", "logger": "authentik.asgi", "method": "POST", "pid": 10514, "remote": "127.0.0.1", "request_id": "dbc6b792cbc247dd8a879fb0dd8ec8f4", "runtime": 54, "scheme": "https", "status": 200, "timestamp": "2023-05-14T22:29:13.024719", "user": "", "user_agent": "goauthentik.io/outpost/2023.4.1 (provider=Echo server proxy)"}
{"event":"/outpost.goauthentik.io/callback?X-authentik-auth-callback=true&code=942d95ae2232466aa67a89e8bc8f826f&state=NdC1Ol7jMCT8oS_P9oKDQ3J6gvnETS4eWUbMbo4DbRo","host":"echo.domain.tld","level":"info","logger":"authentik.outpost.proxyv2.application","method":"GET","name":"Echo server proxy","remote":"xxx.xxx.xxx.xxx","runtime":"57.903","scheme":"http","size":68,"status":302,"timestamp":"2023-05-14T22:29:13Z","user_agent":"USER_AGENT"}
{"event":"/outpost.goauthentik.io/auth/nginx","host":"echo.domain.tld","level":"info","logger":"authentik.outpost.proxyv2.application","method":"GET","name":"Echo server proxy","remote":"xxx.xxx.xxx.xxx","runtime":"0.308","scheme":"http","size":0,"status":200,"timestamp":"2023-05-14T22:29:13Z","user":"UserName","user_agent":"USER_AGENT"}
{"event":"/outpost.goauthentik.io/auth/nginx","host":"echo.domain.tld","level":"info","logger":"authentik.outpost.proxyv2.application","method":"GET","name":"Echo server proxy","remote":"xxx.xxx.xxx.xxx","runtime":"0.486","scheme":"http","size":0,"status":200,"timestamp":"2023-05-14T22:29:13Z","user":"UserName","user_agent":"USER_AGENT"}
```

</details>

**Version and Deployment (please complete the following information):**

-   authentik version: 2023.4.1
-   Deployment: docker-compose

**Additional context**
Using nginx reverse proxy.

There are also users on Discord experiencing the same behaviour: https://discord.com/channels/809154715984199690/809154716507963434/1101389383300567060


Discussion:
I have the same bug
Same bug here (authentik version 2023.5.3) with traefik (2.10.1) as reverse proxy
I experience the same bug with Nginx as reverse proxy,
Same behaviour with caddy as reverse proxy and adguard (instead of redirecting to `adguard.domain.tld` , it redirect to `adguard.domain.tld/assets/favicon.svg`) on authentik version 2023.6.0
same behaviour with authentik 2023.6.1 and nginx as reverse proxy
I also have a discord thread here: https://discord.com/channels/809154715984199690/1120822602198417479/1120822602198417479

The issue is quite annoying. Does anyone know a workaround?
I wonder if this is the same issue: https://github.com/coder/code-server/issues/5329

If so, then that issue would already exist since Jul 10, 2022. For me that issue never went away, and I still have it today (I just never had the time to make a bug report here in the Authentik repo, sorry 😅)
I am also experiencing this issue that is preventing a PWA from working properly. 
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Still experiencing issue
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
still a huge annoyance
Definitely still an issue.

Resolving patch:
diff --git a/authentik/events/api/tasks.py b/authentik/events/api/tasks.py
--- a/authentik/events/api/tasks.py
+++ b/authentik/events/api/tasks.py
@@ -60,6 +60,8 @@ class Meta:
             "duration",
             "status",
             "messages",
+            "expires",
+            "expiring",
         ]
 
 


Test patch:
diff --git a/internal/outpost/proxyv2/application/mode_forward_caddy_test.go b/internal/outpost/proxyv2/application/mode_forward_caddy_test.go
--- a/internal/outpost/proxyv2/application/mode_forward_caddy_test.go
+++ b/internal/outpost/proxyv2/application/mode_forward_caddy_test.go
@@ -47,16 +47,14 @@ func TestForwardHandleCaddy_Single_Headers(t *testing.T) {
 	a.forwardHandleCaddy(rr, req)
 
 	assert.Equal(t, http.StatusFound, rr.Code)
-	loc, _ := rr.Result().Location()
-	s, _ := a.sessions.Get(req, a.SessionName())
+	loc, st := a.assertState(t, req, rr)
 	shouldUrl := url.Values{
 		"client_id":     []string{*a.proxyConfig.ClientId},
 		"redirect_uri":  []string{"https://ext.t.goauthentik.io/outpost.goauthentik.io/callback?X-authentik-auth-callback=true"},
 		"response_type": []string{"code"},
-		"state":         []string{s.Values[constants.SessionOAuthState].(string)},
 	}
 	assert.Equal(t, fmt.Sprintf("http://fake-auth.t.goauthentik.io/auth?%s", shouldUrl.Encode()), loc.String())
-	assert.Equal(t, "http://test.goauthentik.io/app", s.Values[constants.SessionRedirect])
+	assert.Equal(t, "http://test.goauthentik.io/app", st.Redirect)
 }
 
 func TestForwardHandleCaddy_Single_Claims(t *testing.T) {
@@ -134,14 +132,12 @@ func TestForwardHandleCaddy_Domain_Header(t *testing.T) {
 	a.forwardHandleCaddy(rr, req)
 
 	assert.Equal(t, http.StatusFound, rr.Code)
-	loc, _ := rr.Result().Location()
-	s, _ := a.sessions.Get(req, a.SessionName())
+	loc, st := a.assertState(t, req, rr)
 	shouldUrl := url.Values{
 		"client_id":     []string{*a.proxyConfig.ClientId},
 		"redirect_uri":  []string{"https://ext.t.goauthentik.io/outpost.goauthentik.io/callback?X-authentik-auth-callback=true"},
 		"response_type": []string{"code"},
-		"state":         []string{s.Values[constants.SessionOAuthState].(string)},
 	}
 	assert.Equal(t, fmt.Sprintf("http://fake-auth.t.goauthentik.io/auth?%s", shouldUrl.Encode()), loc.String())
-	assert.Equal(t, "http://test.goauthentik.io/app", s.Values[constants.SessionRedirect])
+	assert.Equal(t, "http://test.goauthentik.io/app", st.Redirect)
 }
diff --git a/internal/outpost/proxyv2/application/mode_forward_envoy_test.go b/internal/outpost/proxyv2/application/mode_forward_envoy_test.go
--- a/internal/outpost/proxyv2/application/mode_forward_envoy_test.go
+++ b/internal/outpost/proxyv2/application/mode_forward_envoy_test.go
@@ -32,16 +32,14 @@ func TestForwardHandleEnvoy_Single_Headers(t *testing.T) {
 	a.forwardHandleEnvoy(rr, req)
 
 	assert.Equal(t, http.StatusFound, rr.Code)
-	loc, _ := rr.Result().Location()
-	s, _ := a.sessions.Get(req, a.SessionName())
+	loc, st := a.assertState(t, req, rr)
 	shouldUrl := url.Values{
 		"client_id":     []string{*a.proxyConfig.ClientId},
 		"redirect_uri":  []string{"https://ext.t.goauthentik.io/outpost.goauthentik.io/callback?X-authentik-auth-callback=true"},
 		"response_type": []string{"code"},
-		"state":         []string{s.Values[constants.SessionOAuthState].(string)},
 	}
 	assert.Equal(t, fmt.Sprintf("http://fake-auth.t.goauthentik.io/auth?%s", shouldUrl.Encode()), loc.String())
-	assert.Equal(t, "http://ext.t.goauthentik.io/app", s.Values[constants.SessionRedirect])
+	assert.Equal(t, "http://ext.t.goauthentik.io/app", st.Redirect)
 }
 
 func TestForwardHandleEnvoy_Single_Claims(t *testing.T) {
@@ -102,15 +100,13 @@ func TestForwardHandleEnvoy_Domain_Header(t *testing.T) {
 	a.forwardHandleEnvoy(rr, req)
 
 	assert.Equal(t, http.StatusFound, rr.Code)
-	loc, _ := rr.Result().Location()
-	s, _ := a.sessions.Get(req, a.SessionName())
+	loc, st := a.assertState(t, req, rr)
 
 	shouldUrl := url.Values{
 		"client_id":     []string{*a.proxyConfig.ClientId},
 		"redirect_uri":  []string{"https://ext.t.goauthentik.io/outpost.goauthentik.io/callback?X-authentik-auth-callback=true"},
 		"response_type": []string{"code"},
-		"state":         []string{s.Values[constants.SessionOAuthState].(string)},
 	}
 	assert.Equal(t, fmt.Sprintf("http://fake-auth.t.goauthentik.io/auth?%s", shouldUrl.Encode()), loc.String())
-	assert.Equal(t, "http://test.goauthentik.io/app", s.Values[constants.SessionRedirect])
+	assert.Equal(t, "http://test.goauthentik.io/app", st.Redirect)
 }
diff --git a/internal/outpost/proxyv2/application/mode_forward_traefik_test.go b/internal/outpost/proxyv2/application/mode_forward_traefik_test.go
--- a/internal/outpost/proxyv2/application/mode_forward_traefik_test.go
+++ b/internal/outpost/proxyv2/application/mode_forward_traefik_test.go
@@ -47,16 +47,14 @@ func TestForwardHandleTraefik_Single_Headers(t *testing.T) {
 	a.forwardHandleTraefik(rr, req)
 
 	assert.Equal(t, http.StatusFound, rr.Code)
-	loc, _ := rr.Result().Location()
-	s, _ := a.sessions.Get(req, a.SessionName())
+	loc, st := a.assertState(t, req, rr)
 	shouldUrl := url.Values{
 		"client_id":     []string{*a.proxyConfig.ClientId},
 		"redirect_uri":  []string{"https://ext.t.goauthentik.io/outpost.goauthentik.io/callback?X-authentik-auth-callback=true"},
 		"response_type": []string{"code"},
-		"state":         []string{s.Values[constants.SessionOAuthState].(string)},
 	}
 	assert.Equal(t, fmt.Sprintf("http://fake-auth.t.goauthentik.io/auth?%s", shouldUrl.Encode()), loc.String())
-	assert.Equal(t, "http://test.goauthentik.io/app", s.Values[constants.SessionRedirect])
+	assert.Equal(t, "http://test.goauthentik.io/app", st.Redirect)
 }
 
 func TestForwardHandleTraefik_Single_Claims(t *testing.T) {
@@ -134,14 +132,12 @@ func TestForwardHandleTraefik_Domain_Header(t *testing.T) {
 	a.forwardHandleTraefik(rr, req)
 
 	assert.Equal(t, http.StatusFound, rr.Code)
-	loc, _ := rr.Result().Location()
-	s, _ := a.sessions.Get(req, a.SessionName())
+	loc, st := a.assertState(t, req, rr)
 	shouldUrl := url.Values{
 		"client_id":     []string{*a.proxyConfig.ClientId},
 		"redirect_uri":  []string{"https://ext.t.goauthentik.io/outpost.goauthentik.io/callback?X-authentik-auth-callback=true"},
 		"response_type": []string{"code"},
-		"state":         []string{s.Values[constants.SessionOAuthState].(string)},
 	}
 	assert.Equal(t, fmt.Sprintf("http://fake-auth.t.goauthentik.io/auth?%s", shouldUrl.Encode()), loc.String())
-	assert.Equal(t, "http://test.goauthentik.io/app", s.Values[constants.SessionRedirect])
+	assert.Equal(t, "http://test.goauthentik.io/app", st.Redirect)
 }
diff --git a/internal/outpost/proxyv2/application/test.go b/internal/outpost/proxyv2/application/test.go
--- a/internal/outpost/proxyv2/application/test.go
+++ b/internal/outpost/proxyv2/application/test.go
@@ -2,6 +2,9 @@ package application
 
 import (
 	"net/http"
+	"net/http/httptest"
+	"net/url"
+	"testing"
 
 	"goauthentik.io/api/v3"
 	"goauthentik.io/internal/outpost/ak"
@@ -45,11 +48,11 @@ func newTestApplication() *Application {
 			Name:                       ak.TestSecret(),
 			ClientId:                   api.PtrString(ak.TestSecret()),
 			ClientSecret:               api.PtrString(ak.TestSecret()),
+			CookieDomain:               api.PtrString(""),
 			CookieSecret:               api.PtrString(ak.TestSecret()),
 			ExternalHost:               "https://ext.t.goauthentik.io",
 			InternalHost:               api.PtrString("http://backend"),
 			InternalHostSslValidation:  api.PtrBool(true),
-			CookieDomain:               api.PtrString(""),
 			Mode:                       api.PROXYMODE_FORWARD_SINGLE.Ptr(),
 			SkipPathRegex:              api.PtrString("/skip.*"),
 			BasicAuthEnabled:           api.PtrBool(true),
@@ -67,3 +70,25 @@ func newTestApplication() *Application {
 	ts.apps = append(ts.apps, a)
 	return a
 }
+
+func (a *Application) assertState(t *testing.T, req *http.Request, response *httptest.ResponseRecorder) (*url.URL, *OAuthState) {
+	loc, _ := response.Result().Location()
+	q := loc.Query()
+	state := q.Get("state")
+	a.log.WithField("actual", state).Warning("actual state")
+	// modify request to set state so we can parse it
+	nr := req.Clone(req.Context())
+	nrq := nr.URL.Query()
+	nrq.Set("state", state)
+	nr.URL.RawQuery = nrq.Encode()
+	// parse state
+	parsed := a.stateFromRequest(nr)
+	if parsed == nil {
+		panic("Could not parse state")
+	}
+
+	// Remove state from URL
+	q.Del("state")
+	loc.RawQuery = q.Encode()
+	return loc, parsed
+}