truqu / elm-oauth2

OAuth 2.0 client-side utils in Elm
MIT License
81 stars 29 forks source link

Feature/request fine tuning #4

Closed KtorZ closed 6 years ago

KtorZ commented 6 years ago

This PR gives extra control over authenticate requests by exposing an extra authenticateWithOpts method to retrieve an access token. This methods grants the ability to fine-tune the request (and decoders) to retrieve an access token.

This should help to cope with non-standard implementation like GitHub API V3 (see #3)

An example of usage could be:

lenientResponseDecoder : Json.Decoder ResponseToken
lenientResponseDecoder =
    Json.map5 OAuth.Decode.makeResponseToken
        OAuth.Decode.accessTokenDecoder
        OAuth.Decode.expiresInDecoder
        OAuth.Decode.refreshTokenDecoder
        OAuth.Decode.lenientScopeDecoder
        OAuth.Decode.stateDecoder

adjustRequest : AdjustRequest ResponseToken
adjustRequest req =
    let
        headers =
            [ Http.header "Accept" ("application/json") ] :: req.headers

        expect =
            Http.expectJson lenientResponseDecoder
    in
        { req | headers = headers, expect = expect }

getToken : String -> Cmd ResponseToken
getToken code =
    let
        req =
            OAuth.AuthorizationCode.authenticateWithOpts adjustRequest <|
                OAuth.AuthorizationCode
                    { credentials = { clientId = "clientId", secret = "secret" }
                    , code = code
                    , redirectUri = "redirectUri"
                    , scope = [ "whatever" ]
                    , state = Nothing
                    , url = "tokenEndpoint"
                    }
    in
        Http.send handleResponse req

EDIT Adjust the expect field in the adjustRequest function to also use the lenient decoder

billstclair commented 6 years ago

I like the idea, and it would solve my problem. But the Decoder (lenientResponseDecoder in the example code) needs to be a parameter to OAuth.AuthorizationCode.authenticateWithOpts, and passed to Internal.makeRequest to use instead of the wired-in responseDecoder, which will, of course, be the Decoder passed by OAuth.AuthorizationCode.authenticate.

KtorZ commented 6 years ago

I am not sure to understand you on that. The internal makeRequest has been changed and now requires a AdjustRequest ResponseToken function as its first argument (identity is provided when using the current authenticate function, and using authenticateWithOpts enables you to provide your own transformation) . This function actually dictates what the request should be, including the decoder. (I now just realized that this isn't illustrated in my example, I will edit and show it).

Thus, by using the authenticateWithOpts and crafting the right adjustRequest function (as now shown in the initial comment), you should be able to provide your own lenient decoder.

billstclair commented 6 years ago

Duh. My bad. I completely missed where the decoder was passed. Please forgive my idiocy.

KtorZ commented 6 years ago

No worries, let's call it a tie ;)

I will move forward and merge this with a small disclaimer in the README about the usage :+1:

KtorZ commented 6 years ago

Please update to elm-oauth2@2.2.0 :tada:

billstclair commented 6 years ago

Thank you, kindly. I'll likely update billstclair/elm-oauth-middleware this weekend. Maybe I'll have its first release in time for Christmas.

billstclair commented 6 years ago

I updated billstclair/elm-oauth-middleware to use truqu/elm-oauth2 version 2.2.0. Removed lots of code that was near copies of yours. Yay!

The commit is here. It builds, the server is running on my web server machine, and I have tested that it works with GitHub, Gmail, Facebook, and Gab.

I found one documentation bug. Here's my adjustRequest definition, a near copy of your example:

adjustRequest : AdjustRequest ResponseToken
adjustRequest req =
    let
        headers =
            Http.header "Accept" "application/json" :: req.headers

        expect =
            Http.expectJson ED.responseTokenDecoder
    in
    { req | headers = headers, expect = expect }

The differences are that I use the decoder elsewhere, so I put it in one of my modules instead of inline, and this:

        headers =
            Http.header "Accept" "application/json" :: req.headers

Your example, in the README, says:

        expect =
            [ Http.header "Accept" ("application/json") ] :: req.headers

which attempts to add List a to the front of List a. Changing those square brackets to parens would fix the problem (my code has no parens, because elm-format removed them).

KtorZ commented 6 years ago

Hopa! Good one. Thanks for reporting :)