clojurekeycloakring

Clojure http classic web app don´t get access token on SSO authentication


I am building a simple http classic web application (request-response) in Clojure in orden to test the integration with Keycloak identity server.

I am ussing ring-oauth2 library, following the steps described in library documentation.

Here is the initialization of my app

(defn app-routes []
  (ring/router
   [["/"
     {:get {:handler (fn [request]
                       (response-handler request views/home-page))}}]]))

(defn wrap-site-defaults [handler]
  (ring.middleware.session/wrap-defaults handler (-> ring.middleware.defaults/site-defaults (assoc-in [:session :cookie-attrs :same-site] :lax)))

(defn wrap-oauth2-config [handler]
  (wrap-oauth2
   handler
   {:keycloak
    {:client-id "my-app"
     :client-secret "***********"
     :authorize-uri "http://localhost:8080/realms/my-realm/protocol/openid-connect/auth"
     :access-token-uri "http://localhost:8080/realms/my-realm/protocol/openid-connect/token"
     :redirect-uri "http://localhost:3300/oauth2/callback"
     :scopes ["openid" "profile" "email"]
     :launch-uri "/login"
     :landing-uri "/"}}))

(defn -main []
  (let [handler (-> (ring/ring-handler (app-routes))
                    (wrap-oauth2-config) 
                    (wrap-site-defaults)
                    (ring.middleware.params/wrap-params))]
    (run-jetty handler {:port 3300 :join? false})
    (println "Server started on port 3300")))

After run the app and git the endpoint http://localhost:3300/login the authenticate process is completed in Keycloak but after the redirection to home page the key :oauth2/access-tokens is not present in the request.

What mistake could I be making? Am I missing some configuration, middleware? Is the order in which I have the middlewares correct?


Solution

  • After a lot of tests and find a great repo as example (Booklog) i fix my problem

    First: Use only ["profile" "email"] scopes inside oauth2 configuration

    Second: Use "/oauth2/done" as landing-uri instead of "/". With this I have managed to decode the access token and build an identity key (:identity) and associate it with the current session.

    Third: correct the order of middlewares

    Aquí comparto como ha quedado mi código

    (defn app-routes []
      (ring/router
       [["/"
         {:get {:handler (fn [request]
                           (response-handler request views/home-page))}}]
        ["/oauth2/done"
         {:get {:handler (fn [request]
                           (let [identity (fetch-identity (get-in request [:oauth2/access-tokens :keycloak :token]))
                                 next-session (assoc (:session request) :identity identity)]
                             (-> (redirect "/")
                                 (assoc :session next-session))))}}] 
        ["/logout"
         {:get {:handler (fn [_]
                           {:status 302
                            :headers {"Location" "http://localhost:8080/realms/my-realm/protocol/openid-connect/logout?client_id=my-clientb&post_logout_redirect_uri=http://localhost:3300"}
                            :session nil})}}]]))
    
    (defn wrap-oauth2-config [handler]
      (wrap-oauth2
       handler
       {:keycloak
        {:client-id "my-client"
         :client-secret "************"
         :authorize-uri "http://localhost:8080/realms/my-realm/protocol/openid-connect/auth"
         :access-token-uri "http://localhost:8080/realms/my-realm/protocol/openid-connect/token"
         :redirect-uri "http://localhost:3300/oauth2/callback"
         :scopes ["profile" "email"]
         :basic-auth? true
         :launch-uri "/login"
         :landing-uri "/oauth2/done"}}))
    
    (defn -main []
      (let [handler (-> (ring/ring-handler (app-routes))
                        (wrap-authentication (backends/session))
                        (wrap-session)
                        (auth/wrap-oauth2-config)
                        (wrap-defaults (-> site-defaults 
                                           (assoc-in [:session :cookie-attrs :same-site] 
                                                     :lax))))]
        (run-jetty handler {:port 3300 :join? false})
        (println "Server started on port 3300")))