A Deep Dive into Debugging an Authentik OIDC userinfo error
I’m using Authentik as a single-sign on provider for all applications in my homelab.
After a recent upgrade from Authentik to the latest version (2024.12.4 -> 2025.8.4), I was no longer able to log into my Gitea instance.
After logging in via OIDC, Gitea simply greeted me with a 500 Internal Server error page.
This is the moment every homelabber dreads: an upgrade breaks a critical service and there’s no one to blame but yourself.

This led me onto a debugging journey that lasted several days and I want to share with you in this post.
# Initial troubleshooting
Given the fact that I had just updated Authentik, the immediate suspicion was of course on Authentik. However, the possibility that Gitea is sending an incorrect (i.e. non-spec compliant) OAuth request to Authentik - which with this recent version of Authentik is no longer tolerated - could not be excluded.
Based on Gitea’s logs, I figured out that Gitea responds with a 500 error because it is not able / not allowed to reach the userinfo OAuth2 endpoint of Authentik:
| |
Based on past experience I know that 403 Forbidden errors are common in an OAuth2 setup when the access token does not have the correct scope, namely it’s missing the openid scope which allows the access token to retrieve additional details about the user itself from the identity provider (IdP).
Then I checked the Authentik logs and found:
| |
Simplified:
| |
Indeed it seems that the token sent by Gitea does not have a scope set!
But why should that be the case all of a sudden?
I was deeply skeptical at this point, so I pulled out the big guns: tcpdump + Wireshark.
| |
Let me quickly explain the command:
-i any: This tells tcpdump to listen on all network interfaces. In a Kubernetes or container environment with virtual networking, this is a lifesaver because you don’t have to guess which specific virtual interface the pod’s traffic is using."(host ... or host ...)": This filter is the most important part. It captures only the traffic to and from the Gitea and Authentik pods on their respective ports, saving me from having to sift through tons of unrelated network noise.-w /tmp/gitea-login.pcap: I’m writing the output to a .pcap file so I can open it in a powerful tool like Wireshark for detailed analysis later, which is much easier than trying to read the stream in the terminal.- In my homelab, I terminate TLS at the ingress controller. This means traffic from the outside world is encrypted, but once it enters my cluster network, communication between services is plain, which makes debugging in situation like these much easier.

Indeed with this additional insight I could check the entire authentication flow and confirm that the access token returned by Authentik does not have the required - in fact it has no scopes at all - despite Gitea requesting the openid email profile scopes.
| |
What the hell?
# Bug report
At this point I was pretty convinced that this must be a bug in the version of Authentik. But despite spending hourse going through the changelogs of several versions, the bug tracker as well as pull requests I couldn’t find any hint that the OIDC behavior was recently changed (deliberately or accidentally). I also couldn’t find any meaningful results on the web when searching for “authentik userinfo 403 Forbidden insufficient scope” or “authentik returns oauth token without scope”. Surely someone else would have run into this issue before with such a common scenario (OAuth2 access tokens used for the userinfo endpoint)?
I decided to put together a small reproducer using oidc-demo-client app:
| |
Then run the demo client and log in via browser:
| |
Just like Gitea before, oidc-client receives a 403 Forbidden response from the userinfo endpoint with the error message: error="insufficient_scope", error_description="The request requires higher privileges than provided by the access token.
So it clearly must be a bug in Authentik!
# AI analysis
Since I had already put together all the evidence (including logs from Gitea and Authentik), I decided to feed it to the AI (Gemini 2.5 Pro in this case). And the result surprised me!
Can you help me troubleshoot this issue with Oauth2 / OIDC? (all the context from before)
Root cause
The key to understanding the problem lies in this line from your Authentik server logs:
| |
This log entry shows that your application correctly requested the openid, profile, and email scopes (scope_given). However, Authentik’s configuration for this provider has no allowed scopes defined (scope_allowed": "set()").
Solution
To fix this, you need to explicitly add the required scopes to your OAuth2 Provider in Authentik.
- Navigate to your Authentik Admin Interface.
- Go to Applications -> Providers.
- Click on the OAuth2 Provider you are using for this application (e.g., gitea2).
- Under the Advanced protocol settings section, locate the Scopes field.
- From the dropdown list, select the scopes your application needs, such as openid, profile, and email.
- Click Update to save the changes.
Okay, I already knew before that something was off with the scopes. But Gemini correctly pointed me in the direction of Authentik’s OAuth2 provider configuration for scopes, which should look like this:

but mine looked like this:

Hummm, there are no scopes selected for this provider, but I don’t even have any scopes available?
That certainly explains why the access token does not have any scope assigned to it.
While the Authentik UI only showed an empty list of property mapppings, the logs revealed that something deeper was broken: an exception by the name of NotImplementedError (again helpfully spotted by Gemini after I gave it a whole lot of the Authentik’s JSON logs).
| |
My best guess is that the Authentik upgrade process included a database migration to move from these old “legacy” mapping types to a new system. For some reason, that migration either failed to run or didn’t complete successfully on my instance, leaving the database in this inconsistent state. This would explain why the UI couldn’t even render the list of available scopes.
Gemini then recommended me to remove the faulty property mapping using the Django shell. However, before I do that I wanted to check how many of the property mappings might be problematic. This took a couple of prompts and back and forth with Gemini, but in the end it managed to produce a working script that I executed as follows:
| |
the script:
| |
Unfortunately it turned out that all the property mappings were somehow broken:
| |
That’s great, just great! /s
Gemini insisted that it was safe to delete these property mappings since they are “legacy”, but I wasn’t so sure about that and how I could get them back in case I needed them.

At the same time, I had a database backup and the database seemed to be in an inconsistent state already, so how much worse could it get by deleting a couple of entries? Gemini suggested to run the following script in the Authentik / Django shell (honestly quite impressive that it can come up with this stuff out of nowhere!) and it worked on the first try.
| |
At this point I noticed in the Authentik web UI that a couple of the Blueprints (specifically the ones related to authentication providers) had failed to execute after the last upgrade. The error message was a bit cryptic, but seemed to point to the property mappings issue we cleaned up just now, so I re-ran those blueprints by clicking on the “Play” button. This time all of them executed successfully.

I check back in the Authentik Oauth2 provider configuration, and now I could finally select the correct scopes for the application!

At last I could log in to Gitea again!
# Conclusion
Well, this was a long and winding post, but I hope you learned something in the process.
Personally, I have two takeaways from this odyssey:
- Always feed your bug reports (including all relevant context) to an AI. If you’ve put enough information together that another human can understand it, it’s definitely worth it to let the AI have a crack at it. In fact, this file was originally called
authentik-bug-report.md! - Check your Authentik Blueprints after each upgrade to make sure they ran successfully as they may give you a clue if anything went wrong during the upgrade or migration process.
Happy debugging!