Skip to content

Instantly share code, notes, and snippets.

@lukewestby
Last active August 5, 2016 23:29
Show Gist options
  • Save lukewestby/ceed6381551530c81ee479a8dc5033f1 to your computer and use it in GitHub Desktop.
Save lukewestby/ceed6381551530c81ee479a8dc5033f1 to your computer and use it in GitHub Desktop.
OAuth 1.0a (3-legged flow) with Elm and Node
port module Main exposing (..)
import Html exposing (..)
import Html.App as Html
import Html.Attributes exposing (..)
import Html.Events exposing (..)
type LoginState
= Waiting
| LoggedIn
| LoggedOut
type alias Model =
{ loginState : LoginState }
loginStateFromBool : Bool -> LoginState
loginStateFromBool loggedIn =
if loggedIn then
LoggedIn
else
LoggedOut
type Msg
= LoginStart
| LoginComplete Bool
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
LoginStart ->
( { loginState = Waiting }
, loginStart ()
)
LoginComplete loggedIn ->
( { loginState = loginStateFromBool loggedIn }
, Cmd.none
)
port loginStart : () -> Cmd msg
port loginComplete : (Bool -> msg) -> Sub msg
subscriptions : Model -> Sub Msg
subscriptions model =
case model.loginState of
Waiting ->
loginComplete LoginComplete
_ ->
Sub.none
init : { loggedIn : Bool } -> (Model, Cmd Msg)
init { loggedIn } =
( { loginState = loginStateFromBool loggedIn }
, Cmd.none
)
view : Model -> Html Msg
view model =
case model.loginState of
Waiting ->
text "Logging in ..."
LoggedIn ->
text "Logged in!"
Loggedout ->
button [ onClick LoginStart ]
[ text "Log in to Twitter" ]
main : Program { loggedIn : Bool }
main =
Html.programWithFlag
{ init = init
, update = update
, subscriptions = subscriptions
, view = view
}
const express = require('express')
, logger = require('morgan')
, session = require('express-session')
, bodyParser = require('body-parser')
, path = require('path')
, Grant = require('grant-express')
const grant = new Grant({
server: {
protocol: process.env.PROTOCOL,
host: protocol.env.URL,
},
twitter: {
key: process.env.CONSUMER_KEY,
secret: process.env.CONSUMER_SECRET,
callback: '/handle_twitter_callback'
}
})
const app = express()
app.use(express.static(path.join(__dirname, '../build')))
app.use(logger('dev'))
app.use(session({ secret: process.env.SESSION_SECRET }))
app.use(grant)
app.use(bodyParser.json())
app.get('/handle_twitter_callback', function (req, res) {
if (req.query.error) {
req.session.auth = null
} else {
req.session.auth = req.query
}
res.send(
`<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<script>
window.opener.postMessage(
${!!req.user.auth},
'${process.env.PROTOCOL}://${process.env.URL}'
)
window.close()
</script>
</body>
</html>
`
)
})
app.get('/', (req, res) => {
res.send(
`<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="user-scalable=no,initial-scale=1,minimum-scale=1,maximum-scale=1,width=device-width" />
<link href='https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,300,600' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="main.css" />
</head>
<body>
<script src="main.js"></script>
<script>
var app = Elm.Main.fullscreen({
loggedIn: ${!!req.session.auth}
})
window.addEventListener('message', function(e) {
app.ports.loginComplete.send(e.data)
})
app.ports.loginStart.subscribe(function() {
window.open('/connect/twitter')
})
</script>
</body>
</html>
`
)
})
app.listen(process.env.PORT, function() {
console.log(`Express server listening on port ${process.env.PORT}`)
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment