goauthentik / goauthentik/authentik
A race condition in authentication flow causes occasional `Flow does not apply to current user.`
- Dominant language
- Python
- Stars
- 25.6k
- Forks
- 2k
- Avg merge
- 1d 4h
- Merged PRs (30d)
- 634
Description
**Describe the bug**
In the user login stage inside the authentication flow, a user may randomly be unable to log in, receiving an error message, “Flow does not apply to current user,” or encountering other similar issues. We discovered a race condition between frontend requests arriving at the backend that may cause this issue.
**To Reproduce**
Steps to reproduce the behavior:
1. Create an authentication source (e.g., Social Login via OIDC) and enable it, which corresponds to the `default-source-authentication` flow while authenticating.
2. Try to log in via this source multiple times or use tools to slow down requests to `/api/v3/flows/executor/default-source-authentication/`.
3. You will be declined by the flow, showing an error message indicating permission denied.
**Expected behavior**
Users should be able to log in normally.
**Screenshots**
1. Branding request responds with a delete cookie header:

2. API request after it will have NO session cookie, causing authentication invalidation:

**Version and Deployment (please complete the following information):**
- authentik version: 2024.8.3
- Deployment: docker-compose
**Additional context**
After debugging, we found the following condition may trigger this issue:
1. Django cycles `session_key` once the user logs in, which purges the old `session_key` in cache storage.
2. Requests sent earlier arrive at the server later with an old session token with a cycled `sid`, causing the cache storage to not find the corresponding `sid`.
3. The server finds the session cookie exists but is not valid since the corresponding key is purged; it returns a `delete_cookie` header which removes the session cookie.
4. Once the request above arrives, the user session will be logged out immediately, even if they have completed the user login stage, which fails the subsequent request to `/api/v3/flows/executor/default-source-authentication/`.
References:
- https://github.com/django/django/blob/6765b6adf924c1bc8792a4a454d5a788c1abc98e/django/contrib/sessions/backends/base.py#L426-L435
- https://github.com/goauthentik/authentik/blob/08041792f22b09600d4286e30555268fc2aa55a5/authentik/root/middleware.py#L84-L91
- https://github.com/goauthentik/authentik/blob/08041792f22b09600d4286e30555268fc2aa55a5/authentik/stages/user_login/stage.py#L97-L102
- https://github.com/django/django/blob/6765b6adf924c1bc8792a4a454d5a788c1abc98e/django/contrib/auth/__init__.py#L114-L126
Currently, the workaround for this issue is under exploration.
Contributor guide
Research direction
Start by reproducing the failure with delayed requests to /api/v3/flows/executor/default-source-authentication/, then read authentik/root/middleware.py, authentik/stages/user_login/stage.py, and the linked Django session and authentication code. Done means concurrent or delayed login requests no longer invalidate the active session or cause the flow to reject the current user.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- django, python
- Domain
- authentication, backend
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100