This package offers some utilities to implement a client-side OAuth 2.0 authentication in Elm. It covers all 4 grant types:
-
Implicit: The most commonly used. The token is obtained directly as a result of a user redirection to an OAuth provider.
-
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.
-
Resource Owner Password Credentials: The token is obtained directly by exchanging the user credentials with an OAuth provider.
-
Client Credentials: The token is obtained directly by exchanging application credentials with an OAuth provider.
The following parts is a walkthrough the first 2 flows. The last 2 are actually pretty straightforward and can be seen (in terms of steps) as a subset of the Authorization Code flow.
elm package install truqu/elm-oauth2.0
A complete example is available here (with the corresponding sources here)
import OAuth
import OAuth.Implicit
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
NoOp ->
model ! []
Authorize ->
model
! [ OAuth.Implicit.authorize
{ clientId = "clientId"
, redirectUri = "redirectUri"
, responseType = OAuth.Token -- Use the OAuth.Token response type
, scope = [ "whatever" ]
, state = Nothing
, url = "authorizationEndpoint"
}
]
init : Navigation.Location -> ( Model, Cmd Msg )
init location =
let
model = {}
in
case OAuth.Implicit.parse location of
-- Nothing to parse, unauthenticated
Err OAuth.Empty ->
model ! []
-- A token has been parsed
Ok (OAuth.OkToken { token }) ->
{ model | token = Just token } ! []
-- An error or, an authorization code has been parsed
Ok _ ->
model ! []
let
req =
Http.request
{ method = "GET"
, body = Http.emptyBody
, headers = OAuth.use token [] -- Add the token to the http headers
, withCredentials = False
, url = "whatever"
, expect = Http.expectJson decoder
, timeout = Nothing
}
in
{ model | token = Just token } ! [ Http.send handleResponse req ]
A complete example is available here (with the corresponding sources here)
import OAuth
import OAuth.AuthorizationCode
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
NoOp ->
model ! []
Authorize ->
model
! [ OAuth.AuthorizationCode.authorize
{ clientId = "clientId"
, redirectUri = "redirectUri"
, responseType = OAuth.Code -- Use the OAuth.Code response type
, scope = [ "whatever" ]
, state = Nothing
, url = "authorizationEndpoint"
}
]
Authenticate res ->
case res of
-- Http request didn't go through
Err err ->
model ! []
-- Token received from the server
Ok (OAuth.OkToken { token }) ->
-- Something else received from the server
Ok _ ->
model ! []
init : Navigation.Location -> ( Model, Cmd Msg )
init location =
let
model = {}
in
case OAuth.AuthorizationCode.parse location of
-- Nothing to parse, unauthenticated
Err OAuth.Empty ->
model ! []
-- A token has been parsed
Ok (OAuth.OkCode { code }) ->
let
req =
OAuth.AuthorizationCode.authenticate <|
OAuth.AuthorizationCode
{ credentials = { clientId = "clientId", secret = "secret" }
, code = code
, redirectUri = "redirectUri"
, scope = [ "whatever" ]
, state = Nothing
, url = "tokenEndpoint"
}
in
model [ Http.send Authenticate req ]
-- An error or, an authorization code has been parsed
Ok _ ->
model ! []
let
req =
Http.request
{ method = "GET"
, body = Http.emptyBody
, headers = OAuth.use token [] -- Add the token to the http headers
, withCredentials = False
, url = "whatever"
, expect = Http.expectJson decoder
, timeout = Nothing
}
in
{ model | token = Just token } ! [ Http.send handleResponse req ]