Skip to content

leaonline/jwt

Repository files navigation

Leaonline JWT

Project Status: Active – The project has reached a stable, usable state and is being actively developed. Test suite GitHub License

A simple JWT implementation that you can add to your Meteor applications in order to share data without the need of a shared database or shared authentication system (such as OAuth providers).

It currently uses node jwt (njwt) but can be easily replaced with any other JWT library.

Usage

First install the package on both applications via

$ meteor add leaonline:jwt

Make sure you understand consumer and provider applications. The consumer is the application that requests data from the provider application. The provider is the application that sends data to the consumer application. Consumer has to be able to connect to the provider application via DDP.

In theory, both apps can be consumer and provider at the same time, so you can share data in both directions.

Create JWTs on the consumer side

On the consumer side you want to create a JWT factory. Before you can do that, you need to add your jwt credentials to the Meteor settings (settings.json) of applications:

{
  "jwt": {
    "key": "your-secret-key",
    "sub": "a-subject-or-username-or-id",
    "expires": 30000
  }
}

Now you can create a token factory:

import { Meteor } from 'meteor/meteor'
import { createJWTFactory } from 'meteor/leaonline:jwt'

const { jwt } = Meteor.settings

const tokenFactory = createJWTFactory({
  url: Meteor.absoluteUrl(), // you can also define a custom URL here
  key: jwt.key,
  sub: jwt.sub,
  expires: jw.expires, // optional, defaults to 60000 ms
  debug: console.debug // optional
})

Now you can generate new JWTS for different methods or publications (or http) endpoints. Let's say you want to consume a method, named getUserData from the provider app, then you can create a JWT like this:

const token = tokenFactory({ name: 'getUserData' })
const remote = DDP.connect('https://provider-app.com')

// ... on successfully connected

remote.call('getUserData', { token }, (error, result) => {
  // ... process response
})

Validate JWTs on the provider side

On the provider side you want to create a JWT validator so you can validate, if the consumer is allowed to call your methods or publications.

First, you need to add the same jwt credentials to the Meteor settings (settings.json) and define allowed / blocked consumers, using a positive list and/or negative list:

{
  "jwt": {
    "key": "your-secret-key",
    "hosts": [
      {
        "url": "https://consumer-app.com",
        "sub": "a-subject-or-username-or-id"
      }
    ]
  }
}
import { Meteor } from 'meteor/meteor'
import { createJWTValidator } from 'meteor/leaonline:jwt'

const { jwt } = Meteor.settings
const validator = createJWTValidator({
  key: jwt.key,
  positives: jwt.hosts, // optional, defaults to [],
  negatives: [], // optional, defaults to []
  debug: console.debug // optional
})

Meteor.methods({
  getUserData({ token }) {
    const { valid, reason } = validator(token, 'getUserData')

    if (!valid) {
      throw new Meteor.Error('unauthorized', `JWT validation failed: ${reason}`)
    }
    
    // ... process the request, e.g. return user data
    return { userId: '12345', name: 'John Doe' }
  }
})

Using a Mixin (for ValidatdMethod)

You can also use a mixin for validated methods that automatically validates the JWT and removes it when passing:

import { Meteor } from 'meteor/meteor'
import { createJWTValidator } from 'meteor/leaonline:jwt'

const { jwt } = Meteor.settings
const validator = createJWTValidator({
  key: jwt.key,
  positives: jwt.hosts, // optional, defaults to [],
  negatives: [], // optional, defaults to []
  debug: console.debug // optional
})

export const validteJWTMixin = options => {
  const { name, validate } = options
  
  options.validate = args => {
    const { token, ...data } = args
    const { valid, reason } = validator(token, name)
    
    if (!valid) {
      throw new Meteor.Error('unauthorized', `JWT validation failed: ${reason}`)
    }
    
    // if we remove token then we don't need
    // to consider it in the method validations
    delete data.token
    
    // run the original validation
    validate(data)
  }
  
  return options
}

Contributing / development

Make sure to run lint, format and test before committing your changes. Please use conventional commit messages, so we can generate a changelog automatically.

License

MIT, see LICENSE

About

simple two-sided jwt integration. server only

Resources

License

Stars

Watchers

Forks

Packages

No packages published