Skip to content

Instantly share code, notes, and snippets.

@neoeinstein
Last active March 2, 2017 08:22
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save neoeinstein/786803ad0459c5faa6274575d1cfcc92 to your computer and use it in GitHub Desktop.
Save neoeinstein/786803ad0459c5faa6274575d1cfcc92 to your computer and use it in GitHub Desktop.
Elm Example for interoperating with Auth0. Note that much of this was culled out of an existing code-base, so may need some minor edits to work correctly for you. Presumes that Elm.Main is transpiled into elm.js
module Auth0
( AuthenticationState(..), AuthenticationError, AuthenticationResult
, Options, defaultOpts
, LoggedInUser, UserProfile, Token
, showLock, showLockSignal
, mapResult
) where
import Effects exposing (Effects, Never)
import Signal exposing (Address,Mailbox,mailbox)
import Task exposing (Task)
type alias LoggedInUser =
{ profile: UserProfile
, token: Token
}
type AuthenticationState
= LoggedOut
| LoggedIn LoggedInUser
type alias Options =
{ }
type alias UserProfile =
{ email : String
, email_verified : Bool
, name : String
, nickname : String
, picture : String
, given_name : String
, family_name : String
, user_id : String
}
type alias Token = String
type alias AuthenticationError =
{ name : String
, code : String
, description : String
, statusCode : Int
}
type alias AuthenticationResult = Result AuthenticationError LoggedInUser
showLockMailbox : Signal.Mailbox Options
showLockMailbox = Signal.mailbox defaultOpts
showLockSignal = showLockMailbox.signal
showLock : Options -> Task Never ()
showLock =
Signal.send showLockMailbox.address
mapResult : Signal { err: Maybe AuthenticationError, ok: Maybe LoggedInUser } -> Signal AuthenticationResult
mapResult =
Signal.map <| \result ->
case (result.err, result.ok) of
(Just msg, _) -> Err msg
(Nothing, Nothing) -> Err { name="unknown", code="unknown", statusCode=500, description="No information was received from the authentication provider" }
(Nothing, Just user) -> Ok user
defaultOpts : Options
defaultOpts = { }
module Authentication
( Msg(..), Model
, init, update
, mapResult
) where
import Effects exposing (..)
import Auth0 exposing (..)
type Msg
= NoOp
| AuthenticationResult AuthenticationResult
| ShowLogIn
| LogOut
type alias Model =
{ state : AuthenticationState
, lastError : Maybe AuthenticationError
}
init : Model
init =
{ state = LoggedOut
, lastError = Nothing
}
update : Msg -> Model -> (Model, Effects Msg)
update msg model =
case msg of
NoOp ->
(model, Effects.none)
AuthenticationResult result ->
let
(newState, error) =
case result of
Ok user -> (LoggedIn user, Nothing)
Err err -> (model.state, Just err)
in
({ model | state = newState, lastError = error }, Effects.none)
ShowLogIn ->
let
effect =
showLock defaultOpts
|> Effects.task
|> Effects.map (\_ -> NoOp)
in
(model, effect)
LogOut ->
({ model | state = LoggedOut }, Effects.none)
mapResult : Signal Auth0.AuthenticationResult -> Signal Msg
mapResult =
Signal.map AuthenticationResult
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<script src="//cdn.auth0.com/js/lock-9.1.min.js"></script>
<script src="/elm.js"></script>
<script src="/index.js"></script>
</body>
</html>
var auth0lock = Auth0Lock("client-id", "TENANT.auth0.com");
var main = Elm.fullscreen(Elm.Main, {
auth0authResult: {err:null, ok:null}
});
main.ports.auth0showLock.subscribe(function(opts) {
auth0lock.showSignin(opts,function(err,profile,token) {
var result = {err:null, ok:null};
if (!err) {
result.ok = {profile:profile,token:token};
} else {
result.err = err.details;
}
main.ports.auth0authResult.send(result);
});
});
module Main (..) where
import Debug exposing (log)
import Html exposing (Html)
import Effects exposing (Effects, Never)
import Task exposing (Task)
import StartApp exposing (start)
import Auth0
import Model exposing (Model)
import Update exposing (init, update, actions)
import View exposing (view)
port initialPath : String
app : StartApp.App Model
app =
start
{ init = init
, update = update
, view = view
, inputs = actions (Auth0.mapResult auth0authResult) }
main : Signal Html
main =
app.html
port tasks : Signal (Task Never ())
port tasks =
app.tasks
-- Auth0 Ports
port auth0showLock : Signal Auth0.Options
port auth0showLock = Auth0.showLockSignal
port auth0authResult : Signal { err: Maybe Auth0.AuthenticationError, ok: Maybe Auth0.LoggedInUser }
module Model (..) where
import Authentication
type Action
= Authentication Authentication.Msg
type alias Model = { auth : Authentication.Model }
module Update (..) where
import Effects exposing (Effects, none)
import Auth0 exposing (AuthenticationResult)
import Authentication
import Model exposing (..)
init : Model
init = { auth = Authentication.init }
update : Action -> Model -> (Model, Effects Action)
update msg model =
case msg of
Authentication msg ->
let
(newAuth, effects) = Authentication.update msg model.auth
in
({ model | auth = newAuth}, effects |> Effects.map Authentication)
actions : Signal (AuthenticationResult) -> List (Signal Action)
actions auth0authResult =
[ Authentication.mapResult auth0authResult |> Signal.map Authentication ]
module View (..) where
import Html exposing (..)
import Html.Events exposing (..)
import Html.Attributes exposing (..)
import Signal exposing (Address)
import Authentication
import Auth0
import Model exposing (..)
loggedOutUser : Address Action -> Action -> Html
loggedOutUser addr loginAction =
div []
[ text "Log in to see information about you"
, button
[ onClick addr loginAction ]
[ text "Login" ]
]
loggedInUser : Address Action -> Action -> Auth0.UserProfile -> Html
loggedInUser addr logoutAction profile =
div []
[ div []
[ img [ src profile.picture ] []
, div [ style [ ("margin-left", "1em"), ("margin-right", "1em") ] ] [ text profile.name ]
, button
[ onClick addr logoutAction ]
[ text "Logout" ]
]
, ul []
[ li [] [ text <| "Given name: " ++ profile.given_name ]
, li [] [ text <| "Family name: " ++ profile.family_name ]
, li [] [ text <| "Email: " ++ profile.email ]
]
]
view : Address Action -> Authentication.Model -> Html
view addr auth =
case auth.state of
Auth0.LoggedIn userData ->
loggedInUser addr (Authentication Authentication.LogOut) userData
Auth0.LoggedOut ->
loggedInUser addr (Authentication Authentication.ShowLogIn)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment