Integrate with Auth0 from Clojure. This repo contains a middleware and some Ring handlers that mostly mirror the functionality in the official Auth0 Servlet, with the notable exception that this library implements Auth0 in a completely statelesss manner (e.g. no sessions).
Add to :dependencies
in your project.clj:
[auth0-ring "0.4.4"]
The middleware and handlers assumes the existence of :cookies
and
:query-params
in the Ring request map, meaning you should make sure to enable
the corresponding middlewares:
(ns your.app
(:require [ring.middleware.cookies :refer [wrap-cookies]]
[ring.middleware.params :refer [wrap-params]]))
(def handler (-> your-web-handler
wrap-params
wrap-cookies))
The official Auth0 Java introduction provides much more details and background on how to use this code, the flow, related specs and so on.
If you just want the distilled version of how to use this library in Clojure, read on.
The library includes a middleware that will verify the user's JSON Web Token
(JWT), if any, and deserialize it into (:user req)
. It does not provide a
middleware for requiring logged in users. It also provides handlers that
implement the authentication callback, add a CSRF token/nonce to the login form,
and implements logout from your app and Auth0.
In order to run the sample code in this repo (and Readme), you will need some configuration:
{:domain "yourapp.datacenter.auth0.com"
:issuer "https://yourapp.datacenter.auth0.com/"
:client-id "client id"
:signing-algorithm :hs256
:client-secret "client secret"
:scope "openid user_id name nickname email picture"
:callback-path "/auth/callback"
:error-redirect "/login"
:success-redirect "/"
:logout-handler "/auth/logout"
:logout-redirect "/"}
To run the provided sample code, put this in resources/config.edn
.
We'll be using Auth0's Lock for logins. Follow the link to learn how to customize it.
The login page pulls a few values from your configuration, as well as the
:nonce
from the request. In order to make this available, wrap the handler in
auth0-ring.handlers/wrap-login-handler
:
(def login
(auth0-handlers/wrap-login-handler
(fn [req]
{:status 200
:headers {"Content-Type" "text/html"}
:body (str "<!DOCTYPE html>
<html>
<head>
<title>Login</title>
</head>
<body>
<script src='https://cdn.auth0.com/js/lock/10.9.1/lock.min.js'></script>
<script>var lock = new Auth0Lock(
'" (:client-id config) "',
'" (:domain config) "', {
auth: {
params: {
scope: '" (:scope config) "',
state: 'nonce=" (:nonce req) "&returnUrl=" (get-in req [:query-params "returnUrl"]) "'
},
responseType: 'code',
redirectUrl: window.location.origin + '" (:callback-path config) "'
}
});
lock.show();</script>
</body>
</html>")})))
Then create your web handler:
(ns auth0-clj.app
(:require [auth0-ring.handlers :as auth0]
[auth0-ring.middleware :refer [wrap-token-verification]]
[ring.middleware.cookies :refer [wrap-cookies]]
[ring.middleware.params :refer [wrap-params]]))
;; config ...
;; login handler ...
(defn auth-callback [auth0-user]
;; Optional hook for when you need to sync user profile details into a local
;; database, session etc.
;;
;; Refer to the Auth0User API:
;; https://github.com/auth0/auth0-java-mvc-common/blob/master/src/main/java/com/auth0/Auth0User.java
(println (.getUserId auth0-user)))
(defn web-handler [req]
(let [callback-handler (auth0/create-callback-handler config :on-authenticated auth-callback)
logout-callback-handler (auth0/create-logout-callback-handler config)
logout-handler (auth0/create-logout-handler config)]
(case (:uri req)
"/login" (login-handler req)
"/auth/callback" (callback-handler req)
"/auth/logout" (logout-callback-handler req)
"/logout" (logout-handler req)
"/favicon.ico" {:status 404})))
(def handler (-> #'web-handler
(wrap-token-verification config)
wrap-params
wrap-cookies))
After going through the login, you should now see (:user req)
in your web
handlers.
Copyright © 2017 Christian Johansen
Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.
Copyright © 2017 Christian Johansen. All rights reserved.
- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.