Configuring redirects in Kong preserving query parameters

I have an application that is available at http:://host/context/ . I want to configure Kong such that the URLs http:://host/ and http://host/context get redirected to http:://host/context/.

I can easily do this with a combination of request-termination & response-transformer plugins… the catch is: I need to also forward query parameters. So, this is the behaviour I want:

  • User visits http:://host/ → redirected to /context/
  • User visits http:://host/context → redirected to /context/
  • User visits http:://host/?param=value → redirected to /context/?param=value
  • User visits http:://host/context?param=value → redirected to /context/?param=value

I’m using Kong in DB-less mode and my configuration for the redirects is:

services:
- name: my-redirects
  url: http://localhost:8080/
  routes:
  - name: redirect-route
    paths:
    - /context$
    - /$
  plugins:
  - name: request-termination
    config:
      status_code: 301
      message: Redirect to main page...
  - name: response-transformer
    config:
      add:
        headers:
        - Location:/context/

Is there some way to modify this portion of the configuration:

add:
  headers:
  - Location:/context/

with something that also includes the query params in the request? I expect to be able to do something like:

add:
  headers:
  - Location:/context/$query_params

Or should I modify the Kong’s NGINX configuration? (how do I do this though? I’d like to avoid using a custom docker image, is it possible to just put the location portion and tell Kong to include it inside its template via env vars?)

To give a bigger picture. My application uses Keycloak and OpenID connect for authentication, so Kong is the R.P. Moreover Keycloak has Azure as Brokered Identity Provider.

The problem with the redirects is that if I go to http:://host/context, I get redirected to Keycloak (good) I authenticate but in the end I get stuck in a redirect loop that ends with “too many redirects” because Keycloak redirects to something like http:://host/context?state=…&other=… which gets redirected to http:://host/context/ which gets redirected to a keycloak url http:://keycloak/auth/realms/my-realm/… which redirects to http:://host/context?state=…&other=… etc.

I believe part of the problem is that the redirect to http:://host/context/ does not include the query params and thus some state is missing to complete the authentication.

(note: the double colon in http:: is because otherwise I’m unable to post the topic as a new user)

Hi galzetta,

Let’s leave keycloak for a moment and just focus on the redirect first.

From what you’ve described, it seems that you only need to redirect the request when you hit /, is that right?

You can try below declarative config:

Please note I added /anything in the redirect uri because I am using httpbin as upstream and config.redirect.uri removes the path from service

_format_version: "2.1"
_transform: true

services:
- name: test-service
  url: https://httpbin.org/anything
  routes:
  - name: first-route
    paths:
    - /$
  - name: second-route
    strip_path: false
    paths:
    - /context$

plugins:
- route: first-route
  name: request-transformer
  config:
    replace:
      uri: /anything/context

These two requests should go to the same upstream url.

 curl 'http://localhost:8000?abc=efg' -s | jq .url
"https://localhost/anything/context?abc=efg"
curl 'http://localhost:8000/context?abc=efg' -s | jq .url
"https://localhost/anything/context?abc=efg"

No, I don’t care about upstream services. I want a redirect to the URL with the ending / and preserve the query parameters.

As I said, a browser visiting http:://host/ should never hit any upstream, it should just receive a redirect to the http::/host/context/ URL and this works… the problem is that if a user goes to http::/host/?a=b I want this to be redirected (so no upstream should be hit directly) to http::/host/context/?a=b.

Upstreams should be “hit” only when matching the /context/ path.