Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Task/76/add config record #79

Merged
merged 7 commits into from
Dec 4, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,4 @@
pom.xml*
*.jar
*.class
.lein-deps-sum
.lein-failures
.lein-plugins
.lein-env
.lein-*
2 changes: 2 additions & 0 deletions dev-resources/src/friend_oauth2/dev.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
(ns friend-oauth2.dev
(:require [friend-oauth2.config :as config]))
212 changes: 210 additions & 2 deletions docs/source/20-configurtion.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,46 @@
# Configuration Reference

There are two ways in which one may configure use of `friend-oauth2`:

* via two custom maps (`client-config` and `uri-config`), or
* via a single configuration record

The latter is a new method and should not be considered for production use
yet. For those applications that can take a chance on this new feature, we'd
be greatly appreciative for usage, testing in the wild, and any bug reports!


## Legacy Configuration

The map passed to `oauth2/workflow` accepts various optional arguments,
described below. See also the [example handlers][2] for working examples.
described below. See also the code in `examples/src` for working examples.
Here's some code from the Github example:

```clj
(def callback-url (System/getenv "OAUTH2_CALLBACK_URL"))
(def parsed-url (url/url callback-url))

(def client-config
{:client-id (System/getenv "OAUTH2_CLIENT_ID")
:client-secret (System/getenv "OAUTH2_CLIENT_SECRET")
:callback {:domain (format "%s://%s:%s"
(:protocol parsed-url)
(:host parsed-url)
(:port parsed-url))
:path (:path parsed-url)}})

(def uri-config
{:authentication-uri {:url "https://github.com/login/oauth/authorize"
:query {:client_id (:client-id client-config)
:response_type "code"
:redirect_uri callback-url
:scope "user"}}
:access-token-uri {:url "https://github.com/login/oauth/access_token"
:query {:client_id (:client-id client-config)
:client_secret (:client-secret client-config)
:grant_type "authorization_code"
:redirect_uri callback-url}}})
```

* `client-config` holds the basic information which changes from app to app,
regardless of the provider: `:client-id`, `:client-secret`, and the
Expand All @@ -24,4 +62,174 @@ alternate function (`get-access-token-from-params`) supplied to handle
the common case where an access_token is provided as parameters in the
callback request. Simply set the `:access-token-parsefn
get-access-token-from-params` See the
[Facebook and Github examples][2] for reference.
Facebook and Github examples for reference.


## New Configuration

The new way of configuring `friend-oauth2` in an application makes use of the
`friend-oauth2.config/Client` record. Here is some example usage for creating
a new client configuration:

```clj
(require '[friend-oauth2.config :as config]
(config/client
:scope "user"
:auth-uri "https://github.com/login/oauth/authorize"
:token-uri "https://github.com/login/oauth/access_token")
```

Note that if the `:client-id`, `:client-secret`, and `:redirect-uri` arguments
are not proivded, they are taken from the `OAUTH2_CLIENT_ID`,
`OAUTH2_CLIENT_SECRET`, and `OAUTH2_CALLBACK_URL` environment variables.

The `Client` record defines the following
fields:

* `client-id`
* `client-secret`
* `redirect-uri`
* `response-type`
* `scope`
* `state`
* `access-type`
* `prompt`
* `login-hint`
* `include-granted-scopes`
* `code`
* `grant-type`
* `adnview`
* `allow-signup`
* `auth-uri`
* `token-uri`

We recommend using the constructor `friend-oauth2.config/client` which will
populate a client configuration record with default values when not specified
in the constructor.

If they are not provided, they will be looked up in the system environment,
supplying those values instead.

and these are the defaults:

* `client-id`: `(System/getenv "OAUTH2_CLIENT_ID")`
* `client-secret`: `(System/getenv "OAUTH2_CLIENT_SECRET")`
* `redirect-uri`: `(System/getenv "OAUTH2_CALLBACK_URL")`
* `response-type`: `"code"`
* `grant-type`: `"authorization_code"`

and these are set to `nil` by default:

* `scope`
* `state`
* `access-type`
* `prompt`
* `login-hint`
* `include-granted-scopes`
* `adnview`
* `allow-signup`
* `auth-uri`
* `token-uri`

Backwards compatibility with the legacy `friend-oauth2` configuration is
facilitated by several configuration utility functions that perform appropriate
tranformations from the record-based approach.


### Sources

The fields for the record above are the combination of the fields taken from
the OAuth2 services supported by `friend-oauth2`. Each is covered below in its
own sub-section.


#### App.net

[App.net's OAuth2 service][app.net service] supports the following query
string parameters for the authorization phase:

* `client_id`
* `response_type` (value `code`)
* `redirect_uri`
* `scope`
* `state`
* `adnview`

And it supports the following for access code exchange:

* `code`
* `client_id`
* `client_secret`
* `redirect_uri`
* `grant_type` (value `authorization_code`)


#### Facebook

[Facebook's OAuth2 service][facebook service] supports the following query
string parameters for the authorization phase:

* `client_id`
* `response_type` (values `code`, `token`, `code%20token`, or
`granted_scopes`)
* `redirect_uri`
* `scope`
* `state`

And it supports the following for access code exchange:

* `code`
* `client_id`
* `client_secret`
* `redirect_uri`


#### Github

[Github's OAuth2 service][github service] supports the following query
string parameters for the authorization phase:

* `client_id`
* `redirect_uri`
* `scope`
* `state`
* `allow_signup` (values `true` or `false`)

And it supports the following for access code exchange:

* `code`
* `client_id`
* `client_secret`
* `redirect_uri`
* `state`


#### Google

[Google's OAuth2 service][google oauth2 service] supports the following query
string parameters for the authorization phase:

* `response_type` (value `code`)
* `client_id`
* `redirect_uri`
* `scope`
* `state`
* `access_type` (values `online` and `offline`)
* `prompt` (values `none`, `consent`, or `select_account`)
* `login_hint`
* `include_granted_scopes` (values `true` or `false`)


And it supports the following for access code exchange:

* `code`
* `client_id`
* `client_secret`
* `redirect_uri`
* `grant_type` (value `authorization_code`)


[app.net service]: https://developers.app.net/reference/authentication/flows/web/#server-side-flow
[facebook service]: https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow
[github service]: https://developer.github.com/v3/oauth/
[google oauth2 service]: https://developers.google.com/identity/protocols/OAuth2WebServer
6 changes: 3 additions & 3 deletions docs/source/50-examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

The friend-oauth2 project includes the following examples:

* [App.net](https://developers.app.net/reference/authentication/)
* [Facebook (server-side authentication)](https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/)
* [Github](https://developer.github.com/v3/oauth/)
* [Google OAuth 2.0 Login](https://developers.google.com/accounts/docs/OAuth2Login)
* [Facebook (server-side authentication)](https://developers.facebook.com/docs/authentication/server-side/)
* [App.net](https://github.com/appdotnet/api-spec/blob/master/auth.md)
* [Github](http://developer.github.com/v3/oauth/)


## Configuration
Expand Down
60 changes: 60 additions & 0 deletions src/friend_oauth2/config.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
(ns friend-oauth2.config)

(defrecord Client
[client-id
client-secret
redirect-uri
response-type
scope
state
access-type
prompt
login-hint
include-granted-scopes
code
grant-type
adnview
allow-signup
auth-uri
token-uri])

(defn client
[& {
:keys [client-id
client-secret
redirect-uri
response-type
scope
state
access-type
prompt
login-hint
include-granted-scopes
code
grant-type
adnview
allow-signup
auth-uri
token-uri]
:or {client-id (System/getenv "OAUTH2_CLIENT_ID")
client-secret (System/getenv "OAUTH2_CLIENT_SECRET")
redirect-uri (System/getenv "OAUTH2_CALLBACK_URL")
response-type "code"
grant-type "authorization_code"}}]
(->Client
client-id
client-secret
redirect-uri
response-type
scope
state
access-type
prompt
login-hint
include-granted-scopes
code
grant-type
adnview
allow-signup
auth-uri
token-uri))
2 changes: 1 addition & 1 deletion src/friend_oauth2/workflow.clj
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
(s/defn ^:always-validate workflow
"Workflow for OAuth2"
[config :- {(s/required-key :client-config) ClientConfig
s/Any s/Any}];; The rest of config.
s/Any s/Any}] ;; The rest of config.
(fn [request]
(when (is-oauth2-callback? config request)
;; Extracts code from request if we are getting here via OAuth2 callback.
Expand Down