Leaonline JWT
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:
1{ 2 "jwt": { 3 "key": "your-secret-key", 4 "sub": "a-subject-or-username-or-id", 5 "expires": 30000 6 } 7}
Now you can create a token factory:
1import { Meteor } from 'meteor/meteor' 2import { createJWTFactory } from 'meteor/leaonline:jwt' 3 4const { jwt } = Meteor.settings 5 6const tokenFactory = createJWTFactory({ 7 url: Meteor.absoluteUrl(), // you can also define a custom URL here 8 key: jwt.key, 9 sub: jwt.sub, 10 expires: jw.expires, // optional, defaults to 60000 ms 11 debug: console.debug // optional 12})
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:
1const token = tokenFactory({ name: 'getUserData' }) 2const remote = DDP.connect('https://provider-app.com') 3 4// ... on successfully connected 5 6remote.call('getUserData', { token }, (error, result) => { 7 // ... process response 8})
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:
1{ 2 "jwt": { 3 "key": "your-secret-key", 4 "hosts": [ 5 { 6 "url": "https://consumer-app.com", 7 "sub": "a-subject-or-username-or-id" 8 } 9 ] 10 } 11}
1import { Meteor } from 'meteor/meteor' 2import { createJWTValidator } from 'meteor/leaonline:jwt' 3 4const { jwt } = Meteor.settings 5const validator = createJWTValidator({ 6 key: jwt.key, 7 positives: jwt.hosts, // optional, defaults to [], 8 negatives: [], // optional, defaults to [] 9 debug: console.debug // optional 10}) 11 12Meteor.methods({ 13 getUserData({ token }) { 14 const { valid, reason } = validator(token, 'getUserData') 15 16 if (!valid) { 17 throw new Meteor.Error('unauthorized', `JWT validation failed: ${reason}`) 18 } 19 20 // ... process the request, e.g. return user data 21 return { userId: '12345', name: 'John Doe' } 22 } 23})
Using a Mixin (for ValidatdMethod)
You can also use a mixin for validated methods that automatically validates the JWT and removes it when passing:
1import { Meteor } from 'meteor/meteor' 2import { createJWTValidator } from 'meteor/leaonline:jwt' 3 4const { jwt } = Meteor.settings 5const validator = createJWTValidator({ 6 key: jwt.key, 7 positives: jwt.hosts, // optional, defaults to [], 8 negatives: [], // optional, defaults to [] 9 debug: console.debug // optional 10}) 11 12export const validteJWTMixin = options => { 13 const { name, validate } = options 14 15 options.validate = args => { 16 const { token, ...data } = args 17 const { valid, reason } = validator(token, name) 18 19 if (!valid) { 20 throw new Meteor.Error('unauthorized', `JWT validation failed: ${reason}`) 21 } 22 23 // if we remove token then we don't need 24 // to consider it in the method validations 25 delete data.token 26 27 // run the original validation 28 validate(data) 29 } 30 31 return options 32}
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