Coder Social home page Coder Social logo

friend-oauth2's Introduction

friend-oauth2

Build Status Dependencies Status Clojars Project Clojure version

OAuth2 workflow for Clojure/Ring friend framework

Contents

Latest Release

Current version on clojars:

[clojusc/friend-oauth2 "0.2.0"]

Introduction

friend-oauth2 is an OAuth2 (site, RFC) workflow for Friend. Working examples have been implemented for app.net's OAuth2, Facebook's server-side authentication, and Github's OAuth2.

New Maintainer!

Where is Dave Della Costa's version? It's here! The clojusc org is the new maintainer for friend-oauth2. However, there is more to that answer, if you are asking about versions of releases:

0.1.3 & 0.1.3-transitional

What's more, the Clojuse 0.1.3 release of friend-oauth2 is exactly the same as Dave's 0.1.3 release, with the exception that the group ID has been changed to clojusc. All the code, all of the deps, etc., are exactly the same. This is tagged in Github as 0.1.3-transitional. This is provided as a convenience to developers that wish to switch to the new, supported org for friend-oauth2, but don't want to take on any burdens of upgrade maintenance at this time.

0.2.0

This release integrates the wiki documentation, the Codox docs, the README, and the examples from the previously separate friend-oauth2-examples repo.

Documentation

Published friend-oauth2 documentation:

Other versions are also available there (see the "Other Versions" topic).

In addition to generated documentation, the docs at that link also include usage, configuration, and testing instructions, among other topics.

License

Copyright © 2012-2016, Dave Della Costa

Copyright © 2016, Clojure-Aided Enrichment Center

Distributed under the MIT License (http://dd.mit-license.org/)

friend-oauth2's People

Contributors

ddellacosta avatar ekoontz avatar jeluard avatar lynaghk avatar oubiwann avatar pjlegato avatar realyze avatar stuarth avatar tutysara 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  avatar

friend-oauth2's Issues

default extract-access-token fn won't work as-is

The default extract-access-token fn won't work as-is (at least for GitHub [see http://developer.github.com/v3/oauth/, search for 'accept header']) because the "step 4" HTTP POST isn't being sent with an "Accept" header of "application/json". I had to provide a custom :access-token-parsefn of #(-> % :body codec/form-decode (get "access_token")). Perhaps some oauth providers deliver json even if you don't ask for it? Maybe send the Accept header all the time to hopefully constrain the response? (via cemerick)

anti-forgery-token is encoded but not decoded

In https://github.com/ddellacosta/friend-oauth2/blob/master/src/friend_oauth2/util.clj#L17 the anti-forgery-token is form-encoded but it is never decoded before checking it in https://github.com/ddellacosta/friend-oauth2/blob/master/src/friend_oauth2/util.clj#L40.

In case the state contains spaces, the token will have + chars after the encoding and therefore will not be the same. I just found that this is the reason for an endless loop redirecting me back to the provider.

Release 0.3.0

The overall goal of this release is to improve the user experience of friend-oauth2. In particular, the focus will be on:

  • The examples, providing a recommendation for fully backwards-compatible boilerplate reduction.
  • With that done, an effort will be made to bring generalized common services under the friend-oauth2.service namespace, for the convenience of users.

Features:

  • Recommend a best practice for configuring workflows - #49
  • Provide helper namespaces for contributed workflows - #50
  • Add new set of examples that use the new service namespace - #67
  • Provide means of testing supported services - #68
  • Improve Code Documentation - #60

Config URI as a function of request?

I'm working on an app with a staging and production environment, and am having trouble specifying the proper domain. Rather than hardcoding my domains in my config, it'd be useful to be able to pass the request into format-config-url and have behavior like this:

(defn format-config-uri
  "Formats the supplied config uri for passing in to the friend oauth2
   workflow."
  ([client-config req]
     (let [path (-> client-config :callback)
           domain (r/original-url req)]
       (str domain path))))

r/original-url is almost exactly like friend's, except that it strips the URI and query params. Maybe if @cemerick cut that function into two we could reuse original-url.

Thoughts?

Recommend a best practice for configuring workflows

The data structures used to create workflows can be a bit cumbersome, especially for projects that wrap friend-oauth2 or provide convenience functionality on top of friend-oauth2. I have experimented with some fully backwards-compatible mechanisms for lessening this developer/user burden. The use of records and a couple of functions that convert a flat/simple config record to the data structures needed by friend-oauth2 has been an especially clean (and fully optional) approach.

This is probably just going to be a documentation effort more than anything, perhaps showing a new set of examples that use such an approach ...

Tasks:

  • Add links to the official service documentation for all the services in the examples
  • Identify all the fields needed for all the the services in the examples
    • Google
    • Github
    • App.net
    • Facebook
  • Define record that can be used for all supported examples - #76
  • Define utility functions for creating a client and uri configs - #77
  • Update the workflow function so that it can take both the record and the map configurations - #78
  • Document both approaches (separately) in the "Configuration" section of the docs

Part of release #64

Support multiple outh providers in the workflow

Enhance outh2 workflow to allow multiple providers where the user can authenticate using any of them.

Many sites allow the users to login using their credentials with various providers like Google/Facebook/Github etc and adding this will allow clj web apps to do this easily.

Is this alive? Re. Luminus / lib-noir

Hey @ddellacosta are you still maintaining this?

Anyway, I've been struggling to find a way to integrate Friend/Friend-oauth2 with Luminus. The problem being the way lib-noir handles the middleware and the fact that it wouldn't redirect to authorization if :allow-anon? is true, and instead just bubble up the unauthorized exception.

So, after many hours combing the web I finally found that @bzg had the same problem on the Clojure mailing list and posed the question but nobody answered. However, I sniffed around his repositories and found out that he'd indeed found out what to do - thanks @bzg :)

So here it is for posterity, in it's glorious simplicity:

Instead of:

(defroutes routes ;;etc)

(def app
  (handler/site
   (friend/authenticate routes
    {:allow-anon? true
     :workflows [(oauth2/workflow
                  {:client-config client-config
                   :uri-config uri-config
                   :access-token-parsefn get-access-token-from-params
                   :config-auth config-auth})]})))

which is everything you'll ever see in every post and comment about it, do:

(defroutes routes ...)

(def app
  (app-handler
    [auth-routes (friend/authenticate home-routes friend-config) base-routes]
    :middleware (load-middleware)
    ;;etc))

So, don't load friend's middleware through :middleware, just wrap the routes with it.

Custom fn to map access token to friend auth map?

I'm trying to use Github and Google as identity providers for an app via your library.
I can get an access token fine, but what I need to do is use it to retrieve some data (e.g., the user's email address) from the provider and then do a lookup in my own database to determine the appropriate role to return.

It looks like the simplest way to do this would be to allow library consumers to replace the default function,

(make-auth (merge {:identity access-token
                   :access_token access-token}
             (:config-auth config)))

with a custom function that receives the access-token and returns an auth-map or nil.

I'd be happy to implement this and submit a pull request, but I wanted to run it by you first in case I'm missing something.
Any issues with that approach?
Is there a nicer way to handle it?

/cc @cemerick

Foursquare example

As reported originally by @anildigital (here):

I am trying to integrate with Foursquare but I am getting redirected to

http://localhost:3000/auth/callback?code=VUUJP3XHVB3UE3GZSQ3KCKZL5EBVBSXEC0V1YQDGZ2TIHAM4&state=sHpjq6ziK00bzy%2BQc4Nb%2Bw3%2BZy4X0diBFJozdgm4G1o3BEnzEPt9YccZM3dkKcAadXapoDzqlCRvNG#_=_

Looks like it's not fetching accessToken.

Here is the gist https://gist.github.com/anildigital/25bf4c6ecd69d4175d31

I am not sure why fetching accessToken flow is so hidden there.

Provide means of testing supported services

Testing of services will necessarily be manual in nature due to the fact that not every service provides a public sandbox for testing authentication and the additional complexity of using something like Selenium to test the results.

Tasks:

  • Create a config.ini file for all supported services - #69
  • Add envini library as a dep - #70
  • Define manual steps for testing services and document them - #71
  • Explicitly state which services are regularly tested (and thus supported) - #72
  • Provide information to developers/contributors who want to see services added - #73

Part of release #64

Break up workflow/workflow function

By making the workflow function a series of logically separate function calls, we can:

  • make it easier for newcomers to understand the codebase
  • reduce nesting
  • more easily identify explicit bits of code to be overridden (optionally)

(Not yet associated with feature/epic)

Provide helper namespaces for contributed workflows

After fully integrating the examples into this repo (see #43), and recommending a backwards-compatible approach for simplifying workflow configuration (see #49), it might make sense to provide wrappers (in their own namespaces) for workflows against commonly used/contributed services.

Open questions:

  • How supported will these be?
    • provide caveat in the ns docstring
  • Is there a good way to provide testing for them? (Does the service in question provide testing credentials for public use?)
  • Can a testing approach be integrated with TravisCI?

Part of release #64

Infinite redirections

Hello,

I have the following issue with friend-oauth2 :

  The web page "http://localhost:8080/auth/facebook/callback?code=AQDrjoLPsIPKH6JvAJaJKEHNDg...." create too much redirections.

Because of an infinite redirection between

 https://www.facebook.com/dialog/oauth?redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fauth%2Ffacebook%2Fcallback&client_id=........

and

 http://localhost:8080/auth/facebook/callback?code=........

My ring handler is the following :

 (-> routes
     compojure-handler/api
     wrap-params
     wrap-keyword-params
     wrap-session
     wrap-nested-params
     (wrap-resource "public")
     (friend/authenticate
    {
        :allow-anon? true
        :workflows [(oauth2/workflow {
            :client-config client-config
            :uri-config uri-config
            :access-token-parsefn access-token-parsefn
            :config-auth config-auth
        })]
    }
)
 )

If you want more information for help me, it is possible :D, of course !

Thanks !

Need CSRF protections

There's currently nothing provided for CSRF protections. This needs to be baked in, and enforced automagically. (via cemerick)

Generate and publish API Reference docs

  • Add top-level Makefile
  • Add docs.mk include
  • Add targets to docs.mk for:
    • Generating docs using the right profile
    • Running a local dev server to view the generated docs
    • Adding docs for version 0.1.3
    • Adding docs for 0.2.0
    • Publishing the docs to the project gh-pages branch
  • Publish docs to gh-pages
  • Update README with link to published docs

Part of feature #39

Integrate examples into this repo

Tasks:

  • Identify means of keeping source code and example code separate - #44
  • Update project.clj with the selected approach - #45
  • Copy source code from example repo - #46
  • Put deprecation notice on example repo README - #47
  • Add documentation for each example - #48 (depends upon #39)

Part of release #51

Keep redirecting and add up new 'state' in the session

Middleware stack:
(-> app-route
  (friend/authenticate {:allow-anon?          true
                       :default-landing-uri  "/console"
                       :login-uri "/login"
                       :workflows [(workflows/interactive-form
                                    :login-uri "/email-login"
                                    :credential-fn email->user)
                                   (oauth2/workflow
                                    {:client-config fb-client-config
                                    :uri-config fb-uri-config
                                    :access-token-parsefn get-access-token-from-params
                                    :login-uri "/fb-login"
                                    :credential-fn fb-token->user})]})

 wrap-multipart-params
 wrap-keyword-params
 wrap-external-webhooks
 wrap-nested-params
 wrap-params
 wrap-session)
Symptom - 'token' and 'state' entry in 'session' keep adding up. I.e.,
:session 
{:vChUz4SvABgQBgjDvrpQERPo1UFyWYwRNimP81aSrCGZ3leug-AC2sNVLGgBqSzEe0giQ1TrvAGwg9mT "state", 

:-kxHImqfWVN3z7brZOIQePKdpC29oxDnSBAscu38l1AUStAVP-hLu3fR8qD9thzosqEXnlMEGqJQtD-p "state", 

....}

Maybe I am doing something wrong. Or it is a bug. If it is a bug, I can fix it by changing following two functions - making 'state' key and token value not other way around.

(ns friend-oauth2.workflow)

(defn- redirect-to-provider!
  "Redirects user to OAuth2 provider. Code should be in response."
  [{:keys [uri-config]} request]
  (let [anti-forgery-token    (util/generate-anti-forgery-token)

        session-with-af-token (assoc (:session request) :state anti-forgery-token)]
    (-> uri-config
        (util/format-authn-uri anti-forgery-token)
        ring.util.response/redirect
        (assoc :session session-with-af-token))))

(ns friend-oauth2.util)

(defn extract-anti-forgery-token
  "Extracts the anti-csrf state key from the response"
  [{session :session}]
  (:state session))

If the 'state' is in friend's ::identity map, it would be better. Because when logout get called it will be cleared from session by friend's logout function (just a thought, not sure if this is possible).

Create a `config.ini` file for all supported services

Sub-tasks:

  • Put it in ~/.friend-oauth2
  • Name it config.ini
  • Create a section for each supported service
  • Add a new section to the "Testing" doc for service testing
    • Provide documentation of the config.ini file that tests will need to create
    • Outline the manual steps needed for testing one or more services

Depends upon #50

Part of feature #68

Add project documentation to repo

Tasks:

  • Update project.clj with docs profile and codx plugin - #40
  • Generate and publish API Reference docs - #41
  • Convert wiki page to Codox "Topics" - #42
  • Migrate bits of README into Codox "Topics" - #55

Part of release #51

Improve Code Documentation

Tasks:

  • Add docstrings to all example functions - #61
  • Make other functions in workflow namespace public - #62
    • not only will this make them accessible to enterprising users,
    • it will also cause the docstrings for those functions to show up in Codox
  • Document friend-oauth2.workflow/workflow better - #63
  • Provide docstrings for all existing namespaces (not just the functions in the namespaces) - #65
  • Ensure new namespaces for service helper functions have docstrings - #66

Part of release #64

Providing/ implementing a callback uri?

In many of the examples, the client-config map has a callback path, but they aren't defined in the routes.
Google Handler example config/routes

If I had some credential-fn, and config to be passed to friend/authenticate like this:

(defn my-cred-fn [refresh-token]
  (store-in-db refresh-token))

(def oauth-config 
  {:allow-anon? true
   :workflows [(oauth2/workflow
                 {:client-config client-config
                  :uri-config uri-config
                  :config-auth config-auth
                  :credential-fn my-cred-fn})

Where and when would it be called? In regards to #20, how would I know when a refresh token was passed to my-cred-fn? Is the callback uri where a custom credential-fn would be executed? How do you go about implementing one of these callbacks?

Thanks, I realize there are a few questions here, but I think they are connected.

Error compiling friend-oauth2.workflow

When I require friend-oauth2.workflow I get the following exception

my.server => (require '[friend-oauth2.workflow])
CompilerException java.lang.NoClassDefFoundError: Could not initialize class clj_http.client__init, compiling:(friend_oauth2/workflow.clj:1:1)

Do you have an idea why ?

I have tried with friend-oauth2 0.1.1 and 0.1.2, with similar results.

If I clone the repo, launch a REPL and try to require the workflow namespace, it works.

Dependencies in my project.clj

 :dependencies [[org.clojure/clojure "1.6.0"]
                 [org.clojure/clojurescript "0.0-2371" :scope "provided"]
                 [com.domkm/silk "0.0.2"
                  :exclusions [org.clojure/clojure]]

                 ;; server
                 [ring/ring "1.3.1"]
                 [ring/ring-defaults "0.1.2"]
                 [compojure "1.2.0"]
                 [enlive "1.1.5"]
                 [garden "1.2.5"]
                 [http-kit "2.1.16"]
                 [com.cognitect/transit-clj "0.8.259"]
                 [com.cemerick/friend "0.2.0"]
                 [friend-oauth2 "0.1.2"]

                 ;; client
                 [om "0.7.3"]
                 [com.cognitect/transit-cljs "0.8.192"]
                 [racehub/om-bootstrap "0.3.1"
                  :exclusions [org.clojure/clojure]]

                 ;; dev (tasks)
                 [couchdb "0.1.0-SNAPSHOT"]

                 ;; dev (live coding)
                 [figwheel "0.1.4-SNAPSHOT"]
                 [environ "1.0.0"]
                 [com.cemerick/piggieback "0.1.3"]
                 [weasel "0.4.0-SNAPSHOT"]
                 [leiningen "2.5.0"]]

NASA URS Example

It would be good to provide an example for authenticating with NASA's URS OAuth2 service.

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.