Skip to content

Instantly share code, notes, and snippets.

@airtonix
Created January 18, 2015 23:46
Show Gist options
  • Save airtonix/258bba66d0aba4281707 to your computer and use it in GitHub Desktop.
Save airtonix/258bba66d0aba4281707 to your computer and use it in GitHub Desktop.
Sails.Js with Passport.js and Passport-JWT

Intro

session-less use of jwt and passport.js

note: by module I mean either a javascript (.js) or coffeescript (.coffee) file

installation

install the following:

  • sailsjs
  • sails-generate-auth
  • passport-jwt
  • jwt-simple
  • moment
  1. include jwt in your config/passport module
  2. modifiy the api/services/passport module to setup jwt.
  3. create a api/services/protocols/jwt module
  4. create api/policies/hasJsonWebToken module
  5. modify config/policies module to use the new hasJsonWebToken policy, relax policies on UserController.login but require hasJsonWebToken on UserController.index
  6. create api.models.ApiToken module to define valid tokens of various types.
  7. include api/controllers/UserController module to expose a login action, this generates and returns the users JWT access token.
# config/passport.coffee
module.exports =
# other strategies here
# ...
jwt:
protocol: 'jwt'
strategy: require('passport-jwt').Strategy
options:
issuer: 'your website domain'
audience: 'some useful label?'
tokenHeader: 'TOKEN'
# api/services/passport.coffee
# ...
passport.loadStrategies = ()->
strategies = sails.config.passport
Object.keys(strategies).forEach (key)=>
options =
passReqToCallback: true
Config = strategies[key]
Protocol = self.protocols[key]
if key is 'jwt'
_.extend options, Config
@use new Config.strategy sails.config.session.secret, options, Protocol.login
#... other strategies here
module.exports = passport
exports.login = (payload, next)->
query =
id: payload.sub #? not sure here... logging out payload will give you the string you encoded
User
.findOne query
.then (user)->
return next(null, false) unless user
return next null, user
.catch (err)->
return next err
module.exports = (request, response, next)->
request.body = provider: 'jwt'
sails.services.passport.callback request, response, (err, user)->
next(err) unless user or not err
next(null, user)
module.exports =
'*': 'hasJsonWebToken'
UserController:
index: 'hasJsonWebToken'
login: true
jwt = require 'jwt-simple'
moment = require 'moment'
module.exports =
tableName: 'apitoken'
schema: true
meta:
admin: true
public: false
attributes:
user:
model: 'User'
required: true
value:
type: 'string'
valid:
type: 'boolean'
defaultsTo: true
expires:
type: 'datetime'
type:
type: 'string'
defaultsTo: 'access'
enum: [
'access'
'reset'
]
hasExpired: ()->
now = new Date()
diff = (now.getTime() - this.expires)
return diff > sails.config.apitokens.ttl
decode: (data)->
return jwt.decode data, sails.config.session.secret
encode: (data)->
return jwt.encode data, sails.config.session.secret
beforeCreate: (fields, done) ->
sails.log.silly "Creating #{fields.type} token for #{fields.user}"
# Invalidate old tokens related to this user
# clean them out with a scheduled task (protip:
# - http://learnboost.github.io/kue/
# - http://stackoverflow.com/questions/16867001/how-to-schedule-a-job-once-every-thursday-using-kue
encode = @encode
ApiToken.update({user: fields.user, valid: true}, {valid: false})
.then (oldTokens)->
sails.log.silly "Invalidated #{oldTokens.length} old tokens"
.finally ()->
User.findOne()
.where id: fields.user
.then (user)->
fields.valid = true
fields.expires = moment().add(sails.config.apitokens.ttl).toISOString()
value = "#{user.id}#{user.email}#{user.updatedAt}#{fields.expires}"
fields.value = encode value
sails.log.silly 'Encoding token:', value
done()
path = require('path')
url = require('url')
passport = require('passport')
module.exports =
index: (request, response, next)->
user = request.session.user
if not user
return response.unauthorized()
return response.send user
login: (request, response, next)->
sails.services.passport.callback request, response, (err, user)->
if err
sails.log.silly err
return response.serverError()
if user
request.user = user
ApiToken
.create
user: user.id
type: 'access'
.then (token)->
return response.send {access: token.value}
.catch (err)->
return response.serverError err
else
sails.log.silly "Not Found user"
return response.notFound({error: 'invalid user'})
logout: (request, response, next)->
return response.send request.user
@camsjams
Copy link

camsjams commented Aug 5, 2015

This does a pretty good job helping you get setup with JWT and Sails:
https://ericswann.wordpress.com/2015/04/24/nozus-js-1-intro-to-sails-with-passport-and-jwt-json-web-token-auth/

I am not the author of that blog, but I did find both of these resources and thought that @eswann did a better job.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment