tent-auth
Version:
Tent app auth flow implementation.
116 lines (92 loc) • 3.34 kB
JavaScript
var auth = require('..')
// install this module with `npm install tent-discover`
var discover = require('tent-discover')
var port = 4000
// do `npm install express` if you haven't done it yet!
var server = require('express')()
// set the properties of the app to register
// https://tent.io/docs/post-types#app
var app = {
name: 'Äpp',
url: 'http://aepp.com',
redirect_uri: 'http://localhost:'+ port +'/auth/callback/',
types: {
read: [ 'https://tent.io/types/status/v0' ],
write: [ 'https://tent.io/types/status/v0' ]
}
}
// we need a place to persist some data between the redirect and the callback
// you should replace this with something like redis in production
var idPool = 0
var Store = {}
var EntityIdMap = {}
// entry point
// visit http://localhost:{port}/auth/{entity} to get started
// the entity needs to be url encoded!
// use http://meyerweb.com/eric/tools/dencoder/ for example
// example url: http://localhost:4000/auth/http%3A%2F%2Fenti.ty
server.get('/auth/:entity', function(req, res) {
var entity = req.params.entity
var store
// check if the user did previously run through the auth process.
// if he did, we can skip the registration skip and directly obtain refreshed
// tokens ("login")
if((store = Store[EntityIdMap[entity]]) && store.creds) {
console.log('old user %s', entity)
var url = auth.generateURL(store.meta.post.content, store.appID)
store.state = url.state
res.redirect(url.url)
// start the registration process through which every user goes once
} else {
console.log('new user %s', entity)
// create a new store for this user
var id = idPool++
store = Store[id] = {}
EntityIdMap[entity] = id
// discover the entity to get the meta post
// I use the tent-discover module, but you can replace
// it with another one!
discover(entity, function(err, meta) {
if(err) return res.send(err)
store.meta = meta
// we have to clone the app object, to not modify the global one
var cApp = JSON.parse(JSON.stringify(app))
// the callback needs to identify to whom the code belongs
cApp.redirect_uri += id
// register the app with the server
// this step is skipped the next time
auth.registerApp(meta.post.content, cApp,
function(err, tempCreds, appID) {
if(err) return res.send(err)
store.appID = appID
// these temporary credentials,
// only used during authentication
store.tempCreds = tempCreds
//finally generate the auth url ...
var url = auth.generateURL(meta.post.content, appID)
store.state = url.state
// ... and direct the user there!
res.redirect(url.url)
})
})
}
})
// this ressource is only called by the tent server
server.get('/auth/callback/:id', function(req, res) {
console.log('callback id %s', req.params.id)
// get the store corresponding to the id
var store = Store[req.params.id]
// check state
if(store.state !== req.query.state)
return res.send('mismatching state')
// make the final request, to trade the code for permanent credentials
auth.tradeCode(store.meta.post.content, store.tempCreds, req.query.code,
function(err, permaCreds) {
if(err) return res.send(err)
store.creds = permaCreds
// dadaaaaaaa!
res.json(permaCreds)
})
})
server.listen(port)
console.log('server listing on :%s', port)