Giter VIP home page Giter VIP logo

ring-oauth2's Introduction

Ring-OAuth2 Build Status

Ring middleware that acts as a OAuth 2.0 client. This is used for authenticating and integrating with third party website, like Twitter, Facebook and GitHub.

Installation

To install, add the following to your deps.edn file:

ring-oauth2/ring-oauth2 {:mvn/version "0.2.2"}

Or to your Leiningen project file:

[ring-oauth2 "0.2.2"]

Usage

The middleware function to use is ring.middleware.oauth2/wrap-oauth2. This takes a Ring handler, and a map of profiles as arguments. Each profile has a key to identify it, and a map of options that define how to authorize against a third-party service.

Here's an example that provides authentication with GitHub:

(require '[ring.middleware.oauth2 :refer [wrap-oauth2]])

(def handler
  (wrap-oauth2
   routes
   {:github
    {:authorize-uri    "https://github.com/login/oauth/authorize"
     :access-token-uri "https://github.com/login/oauth/access_token"
     :client-id        "abcabcabc"
     :client-secret    "xyzxyzxyzxyzxyz"
     :scopes           ["user:email"]
     :launch-uri       "/oauth2/github"
     :redirect-uri     "/oauth2/github/callback"
     :landing-uri      "/"}}))

The profile has a lot of options, and all have a necessary function. Let's go through them one by one.

The first two keys are the authorize and access token URIs:

  • :authorize-uri
  • :access-token-uri

These are URLs provided by the third-party website. If you look at the OAuth documentation for the site you're authenticating against, it should tell you which URLs to use.

Next is the client ID and secret:

  • :client-id
  • :client-secret

When you register your application with the third-party website, these two values should be provided to you. Note that these should not be kept in source control, especially the client secret!

Optionally you can define the scope or scopes of the access you want:

  • :scopes

These are used to ask the third-party website to provide access to certain information. In the previous example, we set the scopes to ["user:email"]; in other words, we want to be able to access the user's email address. Scopes are a vector of either strings or keywords, and are specific to the website you're authenticating against.

The next URIs are internal to your application and may be any URI you wish that your server can respond to:

  • :launch-uri
  • :redirect-uri
  • :landing-uri

The launch URI kicks off the authorization process. Your log-in link should point to this address, and it should be unique per profile.

The redirect URI provides the internal callback. It can be any relative URI as long as it is unique. It can also be an absolute URI like https://loadbalanced-url.com/oauth2/github/callback

The landing URI is where the middleware redirects the user when the authentication process is complete. This could just be back to the index page, or it could be to the user's account page. Or you can use the optional :redirect-handler key, which expects a Ring handler function. When :redirect-handler is configured, :landing-uri will be ignored.

  • :basic-auth?

This is an optional parameter, which defaults to false. If set to true, it includes the client-id and secret as a header Authorization: Basic base64(id:secret) as recommended by the specification.

Please note, you should enable cookies to be sent with cross-site requests, in order to make the callback request handling work correctly, eg:

(wrap-defaults handler (-> site-defaults (assoc-in [:session :cookie-attrs :same-site] :lax)))

Also, you must make sure that ring.middleware.params/wrap-params is enabled and runs before this middleware, as this library depends on the :query-params key to be present in the request.

Once the middleware is set up, navigating to the :launch-uri will kick off the authorization process. If it succeeds, then the user will be directed to the :landing-uri. Once the user is authenticated, a new key is added to every request:

  • :oauth2/access-tokens

This key contains a map that connects the profile keyword to it's corresponding access token. Using the earlier example of :github profile, the way you'd access the token would be as follows:

(-> request :oauth2/access-tokens :github)

The handler associated with the landing route can check for this token and complete authentication of the user.

PKCE

Some OAuth providers require an additional step called Proof Key for Code Exchange (PKCE). Ring-OAuth2 will include a proof key in the workflow when :pkce? is set to true.

Workflow diagram

The following image is a workflow diagram that describes the OAuth2 authorization process for Ring-OAuth2. It should give you an overview of how all the different URIs interact:

sequenceDiagram
    Client->>Ring Server: GET :launch-uri
    Ring Server-->>Client: redirect to :authorize-uri
    Client->>Auth Server: GET :authorize-uri
    Auth Server-->>Client: redirect to :redirect-uri
    Client->>Ring Server: GET :redirect-uri
    Ring Server->>Auth Server: POST :access-token-uri
    Auth Server->>Ring Server: returns access token
    Ring Server-->>Client: redirect to :landing-uri
    Client->>Ring Server: GET :landing-uri

Contributing

Please see CONTRIBUTING.md.

License

Copyright © 2023 James Reeves

Released under the MIT License.

ring-oauth2's People

Contributors

andreacrotti avatar ballad89 avatar gerdint avatar heliosmaster avatar kah0ona avatar liquidz avatar otann avatar tendant avatar vbedegi avatar weavejester avatar whamtet avatar yatesco avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

ring-oauth2's Issues

Help getting started with ring-oauth2 and Luminus

I'm trying to create a web server backed by github authentication using ring-oauth2 and Luminus. Here's what I've tried:

Added middleware to wrap the wrap-oauth2 function

;; src/clj/project/middleware.clj
;; :require [ring.middleware.oauth2 :refer [wrap-oauth2]] 

(defn wrap-github-oauth2 [handler]
  (wrap-oauth2
   handler
   {:github
    {:authorize-uri    "https://github.com/login/oauth/authorize"
     :access-token-uri "https://github.com/login/oauth/access_token"
     :client-id        "abc"
     :client-secret    "123"
     :scopes           ["user:email"]
     :launch-uri       "/oauth2/github"
     :redirect-uri     "/oauth2/github/callback"
     :landing-uri      "/"}}))

then apply the middleware to my routes using the wrap-routes function

;; src/clj/project/handlers.clj

(mount/defstate app
  :start
  (middleware/wrap-base
    (routes
      (-> #'home-routes
          (wrap-routes middleware/wrap-csrf)
          (wrap-routes middleware/wrap-formats)
          (wrap-routes middleware/wrap-github-oauth2))
      (route/not-found
        (:body
          (error-page {:status 404
                       :title "page not found"}))))))

When I access any of the URLs for home-routes, I don't see any evidence that the middleware has been applied - no oauth2 redirects, no logs. I have no idea how to proceed debugging this - any advice?

Help: how to allow a local administrator to bypass?

Our software ships with a magic administrator user who can do all things everywhere. Users who register via OAuth2 need to be accepted and mapped to internal permissions before they can actually log on.

Do you have any suggestions (other than "magic user? Urgh!") on how to accomplish this? Essentially I want to have a handler for all URLs which:

(defn- ensure-authentication [req]
  (if (magic-user-authenticated? req) continue...)
       (forward-to-oauth2 req)))

If it was only a case of a magic user being able to access a subset of the system then I can see how to do that, but to allow them to access the entirety of the existing system...?

Help :-)

Is the example `ring-defaults` missing the actual handler in README.md?

Hiya - I might be being dumb, but in README.md it states:

(wrap-defaults (-> site-defaults (assoc-in [:session :cookie-attrs :same-site] :lax)))

Isn't this missing the actual handler itself as the first parameter to wrap-defaults:

(wrap-defaults YOUR-ACTUAL-HANDLER (-> site-defaults (assoc-in [:session :cookie-attrs :same-site] :lax)))

(I realise this is probably used with (-> YOUR-ACTUAL-HANDLER (wrap-defaults (-> .... but it tripped me up :-))

Happy to do a PR with updated doc?

Internal Server Error/404 on callback from Youtube API

My profiles for ring-oauth2 are as follows:

{:youtube
       {:authorize-uri "https://accounts.google.com/o/oauth2/v2/auth"
        :access-token-uri "https://accounts.google.com/o/oauth2/v2/token"
        :client-id (System/getenv "YOUTUBE_CLIENT_ID")
        :client-secret (System/getenv "YOUTUBE_CLIENT_SECRET")
        :scopes ["https://www.googleapis.com/auth/youtube"]
        :launch-uri "/auth/youtube"
        :redirect-uri "[site]/auth/youtube/callback"
        :landing-uri "/"}
       :spotify
       {:authorize-uri "https://accounts.spotify.com/authorize"
        :access-token-uri "https://accounts.spotify.com/api/token"
        :client-id (System/getenv "SPOTIFY_CLIENT_ID")
        :client-secret (System/getenv "SPOTIFY_CLIENT_SECRET")
        :launch-uri "/auth/spotify"
        :redirect-uri "[site]/auth/spotify/callback"
        :landing-uri "/"}}

The Spotify profile works perfectly fine, so I'm unsure what is causing the error. Navigating to the launch URI for youtube works correctly, but on the callback, the client receives a 500 Internal Server Error, and in the logs a 404 error is thrown by cljs-http. The full URL being redirected to is [site]/auth/youtube/callback?state=[state]&code=[code]&scope=https://www.googleapis.com/auth/youtube. It seems to me that the library is failing to set up the callback route, but the error isn't very descriptive, so I'm unsure. What might I be doing wrong?

cannot get the token

Hi! I am able to trigger the 2-factor process, and it seems to work all fine.
However I cannot read the received token!

I am using luminus framework with github-oauth2.

In the log I see this error:

Oct 10, 2019 12:48:45 PM org.apache.http.client.protocol.ResponseProcessCookies processCookies
WARNING: Invalid cookie header: "Set-Cookie: has_recent_activity=1; path=/; expires=Thu, 10 Oct 2019 11:48:44 -0000". Invalid 'expires' attribute: Thu, 10 Oct 2019 11:48:44 -0000

This cookie comes from the github oauth authorize response:
{"has_recent_activity":{"path":"/","value":"1"}}

This is my middleware section:

(defn wrap-base [handler]
  (-> ((:middleware defaults) handler)
      
      (wrap-defaults
       (-> site-defaults
           (assoc-in [:security :anti-forgery] false)
           ;(assoc-in [:session :store] (ttl-memory-store (* 60 30)))
           (assoc-in [:session :cookie-attrs :same-site] :lax)
           ))
      (wrap-params)
      (wrap-cookies)          
      (wrap-session)
      (wrap-csrf)
      (wrap-formats)
      (wrap-oauth2 my-oauth-profiles)
      wrap-internal-error))

This is how I try to get the token on the page-handler:

(defn personal-page [request]
  ; Once the user is authenticated, a new key is added to every request:
  ;   :oauth2/access-tokens
  (println "oauth2 tokens: " (-> request :oauth2/access-tokens :github))
  (layout/render request "test.html" {:all (all)}))

Support for dynamic authorization URL params

Some OAuth providers accept additional URL query params as part of the OAuth authorization URL.

Some examples

• Twitter supports screen_name and force_login parameters - https://developer.twitter.com/en/docs/authentication/api-reference/authorize

• Google supports an hd parameter to restrict logins to users with that domain, among some other non-standard params - https://developers.google.com/identity/protocols/oauth2/openid-connect#sendauthrequest

Some of these, like force_login, can be hardcoded in user space when using this middleware.

But it doesn't seem like one can make a POST request to the launch_uri with additional, dynamic params such that they are passed to the provider's authorization URL.

Would the maintainers here be interested in a PR that adds this functionality, or be willing to add it themselves? I can take a stab, but I'm very new to Clojure.

Enhancement: configure middleware for the internal POST calls

So for instance when get-access-token runs, it makes a POST call. This has the default clj-http middleware. This should work fine, but I have ran into an issue where the endpoint that is called contains a bug or returns some unexpected/malformed cookie, causing my POST to crash on wrap-cookies for instance.

I worked around this by forking this repo and wrap (clj-http.client/with-middleware ...) around it.

so the enhancement would be to enable the :middleware profile configuration key, and provide a middleware stack there. If nothing configured, it just doesn't do the with-middleware wrappery.

This makes the lib a bit more resilient, if it crashes. But I wonder if this is too far fetched? My feature suggestion is however fairly non-intrusive.

Middelware does not work with Facebook?

In addition to authenticating with Google (with which the middleware works OK in my app) I would like to offer Facebook login as well.

I do not know whether the fault is the middleware but the Facebook authentication fails receiving an HTTP 400 when making the access token request (to https://graph.facebook.com/v17.0/oauth/access_token). The parameters to the request look fine to me but weirdly the Facebook docs says to make a GET request, though it is my understanding that the OAuth2 spec says it MUST be a POST request. Accordingly, IIUC the Facebook docs the parameters should be sent as query parameters instead of as a form-encoded request body.

So it looks like this is not the fault of the middleware code, but I wonder if anyone else have had success authenticating with Facebook using it, or if the code can be adapted to make it work? I understand it not desired to make work-arounds for specific authentication providers (however prominent), but I just think it's weird that one of the top two Oauth2 authentication providers seemingly don't adhere to the spec at all, so perhaps I'm missing something?

I think that officially Facebook recommends using their own JS SDK for oauth-authentication, though it woud be a nuisance to have to resort to it.

Scary error when forgetting `client_id` or `client_secret`

At the moment if by any chance client_id or client_secret are nil you would eventually get this error:

java.lang.IllegalArgumentException
No implementation of method: :form-encode* of protocol: #'ring.util.codec/FormEncodeable found for class: nil 

Which is kind of cryptic, and the thing is that since most of the times client_id client_secret would passed in (I guess) often as environment variables, it's probably easy to forget they are not set locally, and thus spending a lot of time trying to figure out what's wrong (as it happened to me). Some basic validation at least on these two fields would be enough imho.

Supporting multiple profiles for the same provider?

This might be somewhat an edge case, although I dealt with this in the past when working with Ruby's Omniauth where this issue was addressed IIRC.

Here's my setup:

I have two profiles for Google OAuth:

{:google-sso {:authorize-uri "https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&prompt=select_account"
              :access-token-uri "https://www.googleapis.com/oauth2/v4/token"
              :client-id "test"
              :client-secret "test"
              :redirect-uri "/api/auth/google/callback"
              :landing-uri "/api/auth/google/finalize"

              ;; specific for SSO
              :launch-uri "/api/auth/google/auth"
              :scopes ["openid" "email" "profile"]}

 :google-calendar {:authorize-uri "https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&prompt=select_account&include_granted_scopes=true"
                   :access-token-uri "https://www.googleapis.com/oauth2/v4/token"
                   :client-id "test"
                   :client-secret "test"
                   :redirect-uri "/api/auth/google/callback"
                   :landing-uri "/api/auth/google/finalize"

                   ;; for connecting Google Calendar
                   :launch-uri "/api/auth/google/auth"
                   :scopes ["https://www.googleapis.com/auth/calendar"]}}

Note that :redirect-uri are the same, but scopes, :authorize-uri and :launch-uri are different.

Why this setup? Because Google encourages staged authorization to different resources - as in, if all you need Google access for is signing-in, don't request calendar access as well - not every user will need it. It's something I dealt with in the past with multiple providers, not only Google but also Slack, Qualtrics and probably more that I'm forgetting.

The issue is - because of how the middleware detects the profile during redirect stage:

redirects (into {} (map (juxt parse-redirect-url identity)) profiles)]

a couple of things happen:

  • it will sometimes pick up the wrong profile (depending on ordering)
  • might pass wrong scopes
  • even if the authentication succeeds, the key to get the access token might be also wrong (e.g. I started with :google-sso profile, but access tokens end up in {:oauth2/access-tokens {:google-calendar ... }}

The workaround might look trivial: configure Google's OAuth screen to accept unique redirect URLs. That might work if there's only two, but in realistic scenarios there's at least six (for each environment) and there will be more if/when my application needs to support different regions. And no, Google verifies the whole URL, so appending query params won't work.
To make this even more difficult - any change to the OAuth screen requires going through Google's verification process, which in my experience can be anything from 2hrs to 2 months 😢

On top of that: some API providers support a fixed number of redirect urls (or just one, and you're forced to create separate workspaces/accounts/etc for different environments).

I have a fork which fixes this issue and while the code works, it's a bit hairy - you can see it here: https://github.com/weavejester/ring-oauth2/compare/master...lukaszkorecki:tmp/figure-out-profile-confusion?expand=1

It's all working as expected and all tests are passing, but:

  • the formatting is off
  • I need to come up with a unit test that reproduces this issue and verifies the fix

I'll be more than happy to take this to the finish line, but I'm wondering if there's another way to deal with this.

Thank you

Allow supplying custom success, error handlers

Currently, redirect handler forces redirecting to the landing-uri on success but I often like to do something with the newly gained access token right away, like fetch user details, (open) id, federating with local user account etc. Would you consider supporting optional custom handlers for each profile, e.g. {:success-handler (fn [access-token] ...)}?

redirect-uri and provider differences

Hi -

I'm trying to setup ring-oauth2. I've got oauth2 mostly working in my proof of concept web app (luminus based web app) with google, GitHub and facebook. I've used OAuth2 in other languages so I understand it for the most part but I'm new to Clojure so it may be general misunderstanding. Anyway - I have two questions

  1. What does the redirect-uri do? I have it setup in my code but it never seems to be called and instead the flow takes me directly to the landing-uri. But if I take my redirect-uri handler out of the code it doesn't work. In other languages/frameworks I usually used the redirect-uri to handle post processing of the response like updating the application database by inserting or updating the users table with the token for example but in ring-oauth2 I can't get it to call those functions

  2. It appears that each provider returns different data sets and that this library doesn't seem to handle the POST back to get the actual data I'm trying to access (email read only in my scenario). Note I've put random gibberish into these tokens so they don't actually work in say jwt.io.

e.g. GitHub only returns this data structure
{:github {:token dask348498dslu34ualkdjfkjasdfkajdsf}}

whereas Google returns

:google {:token ya29.3849kasjdflkjalk;sdfjlakjsdfkjdakfdj389jk3jksj-7zpiJ6cU8BgL0wYv6-0AgA5d-S-U8_QN59mDohtGMbQ, :expires #object[org.joda.time.DateTime 0x5f37ef66 2018-04-14T12:55:46.987Z], :id-token eyJhbGciOiJSUzI1NiIsImtpZCI6IjNiNTQ3ODg2ZmY4NWEzNDI4ZGY0ZjYxZGI3M2MxYzIzOTgyYTkyOGUifQ.eyJhenAiOiIzMTQ0MTE3u4k3u4Dcta2JvZTdlZ2F0cjdnM3VzMzhzdDY3NXU1ZmVrZ3FsOGcuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iaGFlbCBFbmdlbGhhcnQiLCJwaWN0dXJlIjoiaHR0cHM6Ly9saDUuZ29vZ2xldXNlcmNvbnRlbnQuY29tLy05dXl3UW5hZzBRcy9BQUFBQUFBQUFBSS9BQUFBQUFBQUJiZyBLAHBLAHBLAHkZlcy9zOTYtYy9waG90by5qcGciLCJnaXZlbl9uYW1lIjoiTWljaGFlbCIsImZhbWlseV9uYW1lIjoiRW5nZWxoYXJ0IiwibG9jYWxlIjoiZW4ifQ.i-_I6yVfqrvp1EO5SjY4f3tu191yyXrbSGUrdt5idExAGA2CPxLqT9ceaOvCI3FaRuV4-CCIuxKR3xNx72qs90EYOKHhPQIb_dnzY4_aDmnQzgNO2c-yegkXBLAHBLAHBLAHGfPvQKtE2DDgpjy9-w99p9KvDfseURsbyILxeaXRDgOzR2qRHhQLnhd4H3wW8Ku_v8kTvupd5FYQe79HFJwhb2tPn2H4PRc0Alb2zsp7fEiIA1iua9LT06HOEzV9_UkAscEb-mCDpmHcmvwY-I7McnF5fiLAEVkK9MaebuKWyGuHnKV1AHzwWM-YfgorQR99L13p7fRaAQ}}}

and facebook returns
:facebook {:token BLAHBLAHBLAHSVR6LYXZAfMSJIiXzg5T4CyaeKj5KbD242pDBPZBVeahGZBu2NyfSQNetTIClCq55TgTfyCZAvwvhNkXBqlgC5ttwICZAr7ZAwBLAHBLAHBLAHnxchJZBzfM3kDgAZDZD, :expires #object[org.joda.time.DateTime 0x2a5ba73b 2018-06-12T15:35:24.426Z]}}

Thanks for any insight. It's possible I'm expecting this to behave like something it's not designed for but before I move on I'd like to learn more if I simply configured it incorrectly or if it's simply a lower level abstraction.

Thanks!
Mike

Logout Flow

Hi, I'm kinda new to developing webapps, so forgive me if this functionality is already present, as I could easily just be unaware of the current ways to implement it.

I'm using ring-oauth2 to implement a "login with "-style login flow. Login works perfectly, but I'd like to implement a logout flow as well. This'd ideally just stop providing the :oauth2/access-tokens entry. This might be possible through an :exit-uri / :session-destroy-uri / :logout-uri profile key.

How to retrieve the access token received from the Provider ?

Hi,

The documentation does not mention how to retrieve the access token issued by the OAuth provider. By the code I understand, it is set to the ring session, however on the landing page the :session of the request map does not contain any information. Is this something related to my handler setup ? I do able to see the cookie is set on the client side something like this

ring-session=5166d573-8150-4935-afdf-f3365f6b05ed;Path=/;HttpOnly;SameSite=Lax

An example would be very helpful.

Thanks,
Bahadir

expires_in is not a number, coming from Microsoft Azure

In format-access-token, the expires_in value I get from the authorization server is the string "3600". The code assumes it can be passed directly to clj-time/seconds as a number, resulting in a ClassCastException. This may be because Microsoft is not following the standard/convention/spec, from some basic googling I see JSON examples showing a number in this field, not a string.

Is this something you would consider supporting in this middelware?

No reader function for tag object when using cookie store

If I have in my ring configuration

(assoc-in site-defaults [:session :store] (cookie-store {:key "a very secret cookie key"}))

I get the error:

java.lang.RuntimeException: No reader function for tag object
	at clojure.lang.EdnReader$TaggedReader.readTagged(EdnReader.java:801)
	at clojure.lang.EdnReader$TaggedReader.invoke(EdnReader.java:783)
	at clojure.lang.EdnReader$DispatchReader.invoke(EdnReader.java:549)
	at clojure.lang.EdnReader.readDelimitedList(EdnReader.java:757)
	at clojure.lang.EdnReader$MapReader.invoke(EdnReader.java:680)
	at clojure.lang.EdnReader.readDelimitedList(EdnReader.java:757)
	at clojure.lang.EdnReader$MapReader.invoke(EdnReader.java:680)
	at clojure.lang.EdnReader.readDelimitedList(EdnReader.java:757)
	at clojure.lang.EdnReader$MapReader.invoke(EdnReader.java:680)
	at clojure.lang.EdnReader.read(EdnReader.java:145)
	at clojure.lang.EdnReader.read(EdnReader.java:111)
	at clojure.lang.EdnReader.readString(EdnReader.java:67)
	at clojure.edn$read_string.invokeStatic(edn.clj:46)
	at clojure.edn$read_string.invokeStatic(edn.clj:37)
	at clojure.edn$read_string.invoke(edn.clj:37)
	at ring.middleware.session.cookie$serialize.invokeStatic(cookie.clj:69)
	at ring.middleware.session.cookie$serialize.invoke(cookie.clj:68)
	at ring.middleware.session.cookie$seal.invokeStatic(cookie.clj:75)
	at ring.middleware.session.cookie$seal.invoke(cookie.clj:72)
	at ring.middleware.session.cookie.CookieStore.write_session(cookie.clj:91)
	at ring.middleware.session$bare_session_response.invokeStatic(session.clj:52)
	at ring.middleware.session$bare_session_response.invoke(session.clj:43)
	at ring.middleware.session$session_response.invokeStatic(session.clj:74)
	at ring.middleware.session$session_response.invoke(session.clj:66)
	at ring.middleware.session$wrap_session$fn__24588.invoke(session.clj:109)
	at ring.middleware.keyword_params$wrap_keyword_params$fn__24630.invoke(keyword_params.clj:36)
	at ring.middleware.nested_params$wrap_nested_params$fn__24688.invoke(nested_params.clj:89)
	at ring.middleware.multipart_params$wrap_multipart_params$fn__24986.invoke(multipart_params.clj:173)
	at ring.middleware.params$wrap_params$fn__25010.invoke(params.clj:67)
	at ring.middleware.cookies$wrap_cookies$fn__24467.invoke(cookies.clj:175)
	at ring.middleware.absolute_redirects$wrap_absolute_redirects$fn__25116.invoke(absolute_redirects.clj:47)
	at ring.middleware.resource$wrap_resource$fn__25026.invoke(resource.clj:37)
	at ring.middleware.content_type$wrap_content_type$fn__25064.invoke(content_type.clj:34)
	at ring.middleware.default_charset$wrap_default_charset$fn__25088.invoke(default_charset.clj:31)
	at ring.middleware.not_modified$wrap_not_modified$fn__17997.invoke(not_modified.clj:53)
	at ring.middleware.x_headers$wrap_x_header$fn__23471.invoke(x_headers.clj:22)
	at ring.middleware.x_headers$wrap_x_header$fn__23471.invoke(x_headers.clj:22)
	at ring.middleware.x_headers$wrap_x_header$fn__23471.invoke(x_headers.clj:22)

When reaching the step of the callback URI.

I suspect associng the access-token to the session is the culprit.

clj-http now requires cheshire 5.9.0

I was getting an error in my oauth2 callback page:

"java.lang.IllegalStateException: Missing #'cheshire.core/parse-stream-strict. Ensure the version of cheshire is >= 5.9.0"

X-Forwarded-* headers are not used for resolving the URI

Function redirect-uri should use X-Forwarded-* header values to resolve the URI, at least request.getHeader("X-Forwarded-Proto"). Currently, if your application is behind a reverse proxy that handles https and you resolve a relative redirect link, the generated URI will have http:// instead of https://.

Implicit dependencies on other middelware

This middleware assumes that the developer already applied wrap-session, wrap-cookie, wrap-params and possibly more. I struggled a bit today before remembering that. I guess this would be a blocker for less experienced ring users.

Would it be a good idea to insert a paragraph about those implicit dependencies in README.md? There already exists a reference to wrap-defaults, but that one is rather specific about a single problem.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.