Skip to content

Commit

Permalink
allow http requests customization, added sample for custom provider
Browse files Browse the repository at this point in the history
  • Loading branch information
OlegZee committed Oct 27, 2015
1 parent 6676695 commit 1706971
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 23 deletions.
22 changes: 21 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,27 @@ You should bind your application session to user id (passed in loginData paramet
loginData contains access_token generated for your oauth provider session. However library does not support this key renewal (e.g. Google's one
expires in one hour). Anyway whenever you want to extract more data from provider you should do it right after login.

While defining configs you could define provider specific 'scopes' so that you can request more specific info from provider.
## Customizing queries
While defining configs you could define:

* provider specific **'scopes'** so that you can request more specific info from provider
* **customize_req**: allows to define specific headers or proxy settings for http webrequest instance

You could also define oauth2 provider not in list:
```fsharp
let oauthConfigs =
defineProviderConfigs (
...
)
// the following code adds "yandex" provider (for demo purposes)
|> Map.add "yandex"
{OAuth.EmptyConfig with
authorize_uri = "https://oauth.yandex.ru/authorize"
exchange_token_uri = "https://oauth.yandex.ru/token"
request_info_uri = "https://login.yandex.ru/info"
scopes = ""
client_id = "xxxxxxxx"; client_secret = "dddddddd"}
```

# References

Expand Down
34 changes: 18 additions & 16 deletions core/HttpCli.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,32 @@
open System.IO
open System.Net

let post (url : string) (data : byte []) =
type DefineRequest = HttpWebRequest -> unit

let send (url : string) meth (define : DefineRequest) =
async {
let request = WebRequest.Create(url) :?> HttpWebRequest
request.Method <- "POST"
request.ContentType <- "application/x-www-form-urlencoded"
request.ContentLength <- int64 data.Length
request.Method <- meth
request.UserAgent <- "suave app" // this line is required for github auth

do define request

use stream = request.GetRequestStream()
stream.Write(data, 0, data.Length)
stream.Close()
use! response = request.AsyncGetResponse()
let stream = response.GetResponseStream()
use reader = new StreamReader(stream)
return reader.ReadToEnd()
}

let get (url : string) =
async {
let request = WebRequest.Create(url) :?> HttpWebRequest
let post (url : string) (define : DefineRequest) (data : byte []) =
send url "POST"
(fun request ->
request.ContentType <- "application/x-www-form-urlencoded"
request.ContentLength <- int64 data.Length

request.UserAgent <- "suave app" // this line is required for github auth
use stream = request.GetRequestStream()
stream.Write(data, 0, data.Length)
stream.Close()

use! response = request.AsyncGetResponse()
let stream = response.GetResponseStream()
use reader = new StreamReader(stream)
return reader.ReadToEnd()
}
do define request)

let get (url : string) = send url "GET"
15 changes: 9 additions & 6 deletions core/OAuth.fs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type ProviderConfig = {
request_info_uri: string
scopes: string
token_response_type: DataEnc
customize_req: System.Net.HttpWebRequest -> unit
}

exception private OAuthException of string
Expand All @@ -27,29 +28,31 @@ exception private OAuthException of string
type LoginData = {Id: string; Name: string; AccessToken: string; ProviderData: Map<string,obj>}
type FailureData = {Code: int; Message: string; Info: obj}

let private Empty = {authorize_uri = ""; exchange_token_uri = ""; request_info_uri = ""; client_id = ""; client_secret = ""; scopes = ""; token_response_type = FormEncode}
let EmptyConfig =
{authorize_uri = ""; exchange_token_uri = ""; request_info_uri = ""; client_id = ""; client_secret = "";
scopes = ""; token_response_type = FormEncode; customize_req = ignore}

/// <summary>
/// Default (incomplete) oauth provider settings.
/// </summary>
let private providerConfigs =
Map.empty
|> Map.add "google"
{Empty with
{EmptyConfig with
authorize_uri = "https://accounts.google.com/o/oauth2/auth"
exchange_token_uri = "https://www.googleapis.com/oauth2/v3/token"
request_info_uri = "https://www.googleapis.com/oauth2/v1/userinfo"
scopes = "profile"
token_response_type = JsonEncode
}
|> Map.add "github"
{Empty with
{EmptyConfig with
authorize_uri = "https://github.com/login/oauth/authorize"
exchange_token_uri = "https://github.com/login/oauth/access_token"
request_info_uri = "https://api.github.com/user"
scopes = ""}
|> Map.add "facebook"
{Empty with
{EmptyConfig with
authorize_uri = "https://www.facebook.com/dialog/oauth"
exchange_token_uri = "https://graph.facebook.com/oauth/access_token"
request_info_uri = "https://graph.facebook.com/me"
Expand Down Expand Up @@ -130,7 +133,7 @@ module private impl =
]

async {
let! response = parms |> util.formEncode |> util.asciiEncode |> HttpCli.post config.exchange_token_uri
let! response = parms |> util.formEncode |> util.asciiEncode |> HttpCli.post config.exchange_token_uri config.customize_req
response |> printfn "Auth response is %A" // TODO log

let access_token = response |> extractToken
Expand All @@ -139,7 +142,7 @@ module private impl =
raise (OAuthException "failed to extract access token")

let uri = config.request_info_uri + "?" + (["access_token", Option.get access_token] |> util.formEncode)
let! response = HttpCli.get uri
let! response = HttpCli.get uri config.customize_req
response |> printfn "/user response %A" // TODO log

let user_info:Map<string,obj> = response |> util.parseJsObj
Expand Down
8 changes: 8 additions & 0 deletions example/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ let main argv =
client_id = ocfg.[key].["client_id"]
client_secret = ocfg.[key].["client_secret"]}
)
// the following code adds "yandex" provider (for demo purposes)
|> Map.add "yandex"
{OAuth.EmptyConfig with
authorize_uri = "https://oauth.yandex.ru/authorize"
exchange_token_uri = "https://oauth.yandex.ru/token"
request_info_uri = "https://login.yandex.ru/info"
scopes = ""
client_id = "xxxxxxxx"; client_secret = "dddddddd"}

(* // you will go that way more likely
let oauthConfigs =
Expand Down

0 comments on commit 1706971

Please sign in to comment.