This is an alternative site for discovering Elm packages. You may be looking for the official Elm package site instead.
We were not able to find the expected elm-package.json file at this tag.
Tag 4.0.1
Committed At 2018-11-06 14:20:08 UTC

Modules

    README

    Elm OAuth 2

    This package offers some utilities to implement a client-side OAuth 2 authorization in Elm. It covers all 4 grant types:

    • Implicit (Recommended): The most commonly used. The token is obtained directly as a result of a user redirection to an OAuth provider. The implicit grant type is used to obtain access tokens (it does not support the issuance of refresh tokens) and is optimized FOR PUBLIC CLIENTS.

    • Authorization Code: The token is obtained as a result of an authentication, from a code obtained as a result of a user redirection to an OAuth provider. The authorization code grant type is used to obtain both access tokens and refresh tokens and is optimized FOR CONFIDENTIAL CLIENTS such as the device operating system or a highly privileged application.

    • Resource Owner Password Credentials: The token is obtained directly by exchanging the user credentials with an OAuth provider. The resource owner password credentials grant type is suitable in cases WHERE THE RESOURCE OWNER HAS A TRUST RELATIONSHIP WITH THE CLIENT.

    • Client Credentials: The token is obtained directly by exchanging application credentials with an OAuth provider. The client credentials grant type MUST ONLY BE USED BY CONFIDENTIAL CLIENTS.

    Getting Started

    Installation

    elm install truqu/elm-oauth2
    

    Usage

    1/ A model ready to receive a token and a message to convey the sign-in request
    type alias Model =
        { redirectUri : Url
        , error : Maybe String
        , token : Maybe OAuth.Token
        , state : String
        }
    
    type Msg = SignInRequested { clientId : String, authorizationEndpoint : String }
    
    2/ Init parses the token from the URL if any, and defines a model
    init : { randomBytes : String } -> Url -> Key -> ( Model, Cmd Msg )
    init { randomBytes } origin _ =
        let
            model =
                { redirectUri = { origin | query = Nothing, fragment = Nothing }
                , error = Nothing
                , token = Nothing
                , state = randomBytes
                }
        in
        case OAuth.parseToken origin of
            OAuth.Empty ->
                ( model, Cmd.none )
    
            OAuth.Success { token, state } ->
                if state /= Just model.state then
                    ( { model | error = Just "'state' mismatch, request likely forged by an adversary!" }
                    , Cmd.none
                    )
    
                else
                    ( { model | token = Just token }
                    , getUserInfo config token
                    )
    
            OAuth.Implicit.Error error ->
                ( { model | error = Just <| errorResponseToString error }
                , Cmd.none
                )
    
    3/ One replies to a sign-in request by redirecting the user to the authorization endpoint
    update : Msg -> Model -> ( Model, Cmd Msg )
    update msg model =
        case msg of
            SignInRequested { clientId, authorizationEndpoint } ->
                let
                    auth =
                        { clientId = clientId
                        , redirectUri = model.redirectUri
                        , scope = []
                        , state = Just model.state 
                        , url = authorizationEndpoint
                        }
                in
                ( model
                , auth |> OAuth.Implicit.makeAuthUrl |> Url.toString |> Navigation.load
                )
    

    Demo

    Complete examples are available here. Resulting applications can be seen on the following links:

    TroubleShooting

    Understanding OAuth roles

    Throughout the library, you'll find terms referring to OAuth well-defined roles:

    • resource owner
      An entity capable of granting access to a protected resource. When the resource owner is a person, it is referred to as an end-user.

    • client
      An application making protected resource requests on behalf of the resource owner and with its authorization. The term "client" does not imply any particular implementation characteristics (e.g., whether the application executes on a server, a desktop, or other devices).

    • authorization server
      The server issuing access tokens to the client after successfully authenticating the resource owner and obtaining authorization.

    • resource server
      The server hosting the protected resources, capable of accepting and responding to protected resource requests using access tokens.

    NOTE: Usually, the authorization server and the resource server are a same entity, or comes from the same entity. So, a simplified vision of this roles can be:

    • resource owner
      The end-user

    • client
      Your Elm app

    • authorization server / resource server
      Google, Facebook, Twitter or whatever OAuth provider you're talking to

    Interacting with GitHub

    GitHub API v3 supports the Authorization Code Flow in order to obtain access tokens for a registered application. However, the implementation presents a flaw which makes it not compliant with the official RFC:

    • By default, GitHub's authorization server will respond with a x-www-form-urlencoded mime-type when trying to exchange the authorization code against an access token (instead of a application/json mime-type as specified in the official RFC).

    • This behavior can be changed by providing an extra Accept: application/json header with the authenticate request. However, by doing so, GitHub's authorization server will encode the scope of the response as a comma-separated list (instead of a space-separated list as specified in the official RFC).

    Hence, this library provides a way to work around this implementation quirks by adjusting the authentication request before it gets sent. To achieve this, one may use the various decoders now exposed in each module to craft a custom transformation function for the authenticateWithOpts functions.

    Here's a small example of how to work around GitHub's API v3 implementation:

    adjustRequest : Http.Request AuthenticationSuccess -> Http.Request AuthenticationSuccess
    adjustRequest req =
        let
            headers =
                Http.header "Accept" ("application/json")  :: req.headers
    
            expect =
                Http.expectJson <| Json.map4 AuthenticationSuccess
                  defaultTokenDecoder
                  defaultRefreshTokenDecoder
                  defaultExpiresInDecoder
                  lenientScopeDecoder
        in
            { req | headers = headers, expect = expect }
    
    
    getToken : String -> Cmd AuthenticationSuccess
    getToken code =
        let
            req =
              adjustRequest <| 
                OAuth.AuthorizationCode.makeTokenRequest <|
                    OAuth.AuthorizationCode
                        { credentials = { clientId = clientId, secret = Nothing }
                        , code = code
                        , redirectUri = redirectUri
                        , scope = scope
                        , state = state
                        , url = tokenEndpoint
                        }
        in
            Http.send handleResponse (Http.request req)
    
    Authentication rquests is the Authorization Flow don't go through

    Most authorization servers don't enable CORS on the authentication endpoints. For this reason, it's likely that the preflight OPTIONS requests sent by the browser return an invalid answer, preventing the browser from making the request at all.

    Why is it so? The authorization request usuallyrequires one's secret; thus making them rather impractical to do perform from a client-side application without exposing those secrets. As a security measure, most authorization servers choose to enforce that those requests are made server-side.

    Generally, this is also what you want, unless you're dealing with a custom authorization server in some sort of isolated environment. OAuth 2.0 is a designed to cover all sort of delegation of permissions, the case of user-facing client-side applications is only one of them; some authorization flows are therefore not necessarily adapted to these cases. Usually, a client-side application will prefer the Implicit Flow over the others.

    Changelog

    CHANGELOG.md