truqu / elm-oauth2 / OAuth.AuthorizationCode

The authorization code grant type is used to obtain both access tokens and refresh tokens and is optimized for confidential clients. Since this is a redirection-based flow, the client must be capable of interacting with the resource owner's user-agent (typically a web browser) and capable of receiving incoming requests (via redirection) from the authorization server.

Quick Start

To get started, have a look at the live-demo and its corresponding source code.

Overview

   +---------+                                +--------+
   |         |---(A)- Auth Redirection ------>|        |
   |         |                                |  Auth  |
   | Browser |                                | Server |
   |         |                                |        |
   |         |<--(B)- Redirection Callback ---|        |
   +---------+          (w/ Auth Code)        +--------+
     ^     |                                    ^    |
     |     |                                    |    |
    (A)   (B)                                   |    |
     |     |                                    |    |
     |     v                                    |    |
   +---------+                                  |    |
   |         |----(C)---- Auth Code ------------+    |
   | Elm App |                                       |
   |         |                                       |
   |         |<---(D)------ Access Token ------------+
   +---------+       (w/ Optional Refresh Token)

After those steps, the client owns a Token that can be used to authorize any subsequent request.

Authorize

makeAuthorizationUrl : Authorization -> Url

Redirects the resource owner (user) to the resource provider server using the specified authorization flow.


type alias Authorization =
{ clientId : String
, url : Url
, redirectUri : Url
, scope : List String
, state : Maybe String 
}

Request configuration for an authorization (Authorization Code & Implicit flows)

parseCode : Url -> AuthorizationResult

Parse the location looking for a parameters set by the resource provider server after redirecting the resource owner (user).

Returns AuthorizationResult Empty when there's nothing


type alias AuthorizationResult =
AuthorizationResultWith AuthorizationError AuthorizationSuccess

Describes errors coming from attempting to parse a url after an OAuth redirection


type AuthorizationResultWith error success
    = Empty
    | Error error
    | Success success

A parameterized AuthorizationResult, see parseTokenWith.


type alias AuthorizationError =
{ error : OAuth.ErrorCode
, errorDescription : Maybe String
, errorUri : Maybe String
, state : Maybe String 
}

Describes an OAuth error as a result of an authorization request failure


type alias AuthorizationSuccess =
{ code : AuthorizationCode
, state : Maybe String 
}

The response obtained as a result of an authorization


type alias AuthorizationCode =
String

A simple type alias to ease readability of type signatures

Authenticate

makeTokenRequest : (Result Http.Error AuthenticationSuccess -> msg) -> Authentication -> RequestParts msg

Builds a the request components required to get a token from an authorization code

let req : Http.Request AuthenticationSuccess
    req = makeTokenRequest toMsg authentication |> Http.request


type alias Authentication =
{ credentials : Credentials
, code : String
, redirectUri : Url
, url : Url 
}

Request configuration for an AuthorizationCode authentication


type alias Credentials =
{ clientId : String
, secret : Maybe String 
}

Describes at least a clientId and if define, a complete set of credentials with the secret. The secret is so-to-speak optional and depends on whether the authorization server you interact with requires a Basic authentication on top of the authentication request. Provides it if you need to do so.

  { clientId = "<my-client-id>"
  , secret = Just "<my-client-secret>"
  }


type alias AuthenticationSuccess =
{ token : OAuth.Token
, refreshToken : Maybe OAuth.Token
, expiresIn : Maybe Basics.Int
, scope : List String 
}

The response obtained as a result of an authentication (implicit or not)


type alias AuthenticationError =
{ error : OAuth.ErrorCode
, errorDescription : Maybe String
, errorUri : Maybe String 
}

Describes an OAuth error as a result of a request failure


type alias RequestParts a =
{ method : String
, headers : List Http.Header
, url : String
, body : Http.Body
, expect : Http.Expect a
, timeout : Maybe Basics.Float
, tracker : Maybe String 
}

Parts required to build a request. This record is given to Http.request in order to create a new request and may be adjusted at will.

JSON Decoders

defaultAuthenticationSuccessDecoder : Json.Decode.Decoder AuthenticationSuccess

Json decoder for a positive response. You may provide a custom response decoder using other decoders from this module, or some of your own craft.

defaultAuthenticationSuccessDecoder : Decoder AuthenticationSuccess
defaultAuthenticationSuccessDecoder =
    D.map4 AuthenticationSuccess
        tokenDecoder
        refreshTokenDecoder
        expiresInDecoder
        scopeDecoder

defaultAuthenticationErrorDecoder : Json.Decode.Decoder AuthenticationError

Json decoder for an error response.

case res of
    Err (Http.BadStatus { body }) ->
        case Json.decodeString OAuth.AuthorizationCode.defaultAuthenticationErrorDecoder body of
            Ok { error, errorDescription } ->
                doSomething

            _ ->
                parserFailed

    _ ->
        someOtherError

Custom Decoders & Parsers (advanced)

Authorize

makeAuthorizationUrlWith : OAuth.ResponseType -> Dict String String -> Authorization -> Url

Like makeAuthorizationUrl, but gives you the ability to specify a custom response type and extra fields to be set on the query.

makeAuthorizationUrl : Authorization -> Url
makeAuthorizationUrl =
    makeAuthorizationUrlWith Code Dict.empty

For example, to interact with a service implementing OpenID+Connect you may require a different token type and an extra query parameter as such:

makeAuthorizationUrlWith
    (CustomResponse "code+id_token")
    (Dict.fromList [ ( "resource", "001" ) ])
    authorization

Authenticate

makeTokenRequestWith : OAuth.GrantType -> Json.Decode.Decoder success -> Dict String String -> (Result Http.Error success -> msg) -> Authentication -> RequestParts msg

Like makeTokenRequest, but gives you the ability to specify custom grant type and extra fields to be set on the query.

makeTokenRequest : (Result Http.Error AuthenticationSuccess -> msg) -> Authentication -> RequestParts msg
makeTokenRequest =
    makeTokenRequestWith
        AuthorizationCode
        defaultAuthenticationSuccessDecoder
        Dict.empty

Json Decoders

defaultExpiresInDecoder : Json.Decode.Decoder (Maybe Basics.Int)

Json decoder for the expiresIn field.

defaultScopeDecoder : Json.Decode.Decoder (List String)

Json decoder for the scope field (space-separated).

lenientScopeDecoder : Json.Decode.Decoder (List String)

Json decoder for the scope field (comma- or space-separated).

defaultTokenDecoder : Json.Decode.Decoder OAuth.Token

Json decoder for the access_token field.

defaultRefreshTokenDecoder : Json.Decode.Decoder (Maybe OAuth.Token)

Json decoder for the refresh_token field.

defaultErrorDecoder : Json.Decode.Decoder OAuth.ErrorCode

Json decoder for the error field.

defaultErrorDescriptionDecoder : Json.Decode.Decoder (Maybe String)

Json decoder for the error_description field.

defaultErrorUriDecoder : Json.Decode.Decoder (Maybe String)

Json decoder for the error_uri field.

Query Parsers

parseCodeWith : Parsers error success -> Url -> AuthorizationResultWith error success

Like parseCode, but gives you the ability to provide your own custom parsers.

parseCode : Url -> AuthorizationResultWith AuthorizationError AuthorizationSuccess
parseCode =
    parseCodeWith defaultParsers


type alias Parsers error success =
{ codeParser : Url.Parser.Query.Parser (Maybe String)
, errorParser : Url.Parser.Query.Parser (Maybe OAuth.ErrorCode)
, authorizationSuccessParser : String -> Url.Parser.Query.Parser success
, authorizationErrorParser : OAuth.ErrorCode -> Url.Parser.Query.Parser error 
}

Parsers used in the parseCode function.

defaultParsers : Parsers AuthorizationError AuthorizationSuccess

Default parsers according to RFC-6749.

defaultCodeParser : Url.Parser.Query.Parser (Maybe String)

Default code parser according to RFC-6749.

defaultErrorParser : Url.Parser.Query.Parser (Maybe OAuth.ErrorCode)

Default error parser according to RFC-6749.

defaultAuthorizationSuccessParser : String -> Url.Parser.Query.Parser AuthorizationSuccess

Default response success parser according to RFC-6749.

defaultAuthorizationErrorParser : OAuth.ErrorCode -> Url.Parser.Query.Parser AuthorizationError

Default response error parser according to RFC-6749.