07
The Japanese channel is working out fine, I think. Though maybe writing there too much is cheating a bit. I'm starting to feel like a single letter there is easier to write than a single word here.
Anyway. I was busy yesterday, so it was hard to write. But today I have time, and I finally want to talk about something technical.
I felt like I was going insane while trying to make the auth setup work at by job. The current setup is:
- Kubernetes
- Ingress-nginx controller
- oauth2 proxy
- Keycloak (OIDC)
The wrench in the gears is that the frontend tries to make a fetch request to the API.
The solution turned out to be "read the documentation", as it always is. So now, let me share what went wrong and what I did to make it right.
Goal
What we were trying to achieve, and what I now understand to be impossible (correct me if I'm wrong an if you know how to reach me) is the following:
- There is a web app, there is some Javascript code that makes a Fetch request.
- If the user is not authenticated, they are redirected to the login page.
- This is not actually relevant because to enter the web app at all, they must have logged in
- If the user is authenticated in Keycloak (meaning they have Keycloak cookies), they might be redirected to Keycloak, but it just confirms everything is fine.
- If the user is authenticated in the oauth2 proxy (meaning they have the oauth2 proxy cookie), they don't even get redirected to Keycloak, and they can just access the resource.
- Using the access token directly as in "Authorization: Bearer" should be avoided.
The Problem - Fetch request can't be redirected to Keycloak.
The key issue in this setup is the combination of redirections and fetch requests. The "Keycloak just confirms everything is fine" part doesn't work. Or, it works, but only when CORS is disabled.
The reason is that at one of the steps of redirection the "Origin" header gets set to "null". It doesn't matter if the originating website is in the allowed origins list or not, unless you literally allow all origins, the request can't be made.
What can be made is a navigation request. If you click a link going to that page, then yes, you can get redirected and end up at that page. But if it's a fetch request - then no, "Origin: null" is set and you can't do anything about it.
The key confusing thing is - this holds true even if you just want Keycloak to confirm an existing session. It makes sense that if you're going to the login page, it needs to be a navigation request that goes to a completely new page. But if you don't actually need to log it, it's the same. The only type of requests that works here are the oauth2 proxy requests and bypass Keycloak completely.
The Solution - Navigation requests.
So, the usual/ideal flow in my app is:
- API URL, is redirected to:
- Oauth2 proxy "start auth process" page, which is redirected to:
- Keycloak authorization endpoint, which is redirected to:
- Oauth2 proxy callback page, which is redirected to:
- API URL, now with credentials.
The problem is, if I make a navigation request at step 1, I go through all the steps (it works!) and end up at step 5. Which is not what I want because it's me navigating to a page when I just wanted to get data from that page. I lose my original place in the app.
So the fetch request to the API doesn't work, and navigation to the API doesn't work. My solution is to manually make the second request.
I'm not sure if it's the settings of the app or just the way oauth2 proxy works, but currently if I get redirected from step 1 to step 2, the page saved as "redirect me back to this page at the very end" is going to be the page from step 1. I don't want to go there, if will make me navigate to step 5 in the end.
What I want to do is repeat this whole process, but to end up on my app's page on step 5. So I write the request #2 manually and I set the "redirect here" parameter to the original app page. Then I make a navigation request, it correctly passes through all the redirections, goes through step 4 (where oauth2 proxy sets up its cookie) and finally follows the redirection parameter I set up, going back to the app, now with a token.
There are some issues left here, but for now I'm very pleased with my solution.
Dead end
At first I tried to skip step 2 and go straight to 3. That doesn't work well, because I'm trying to use the second half of the oauth2 proxy auth process (callback page) without visiting the first half. So I was repeating many auth steps manually before I realized what I was doing.
