JWT authentication with gundb - gun

Can i use JWT authentication with gundb? And if so, would it dramatically slow down my sync speed? I was going to try and implement a test using the tutorial here but wanted to see if there were any 'gotchas' I should be aware of.

The API has changed to use a middleware system. The SEA (Security, Encryption, Authorization) framework will be published to handle stuff like this. However, you can roll your own by doing something like this on the server:
Gun.on('opt', function(ctx){
if(ctx.once){ return }
ctx.on('in', function(msg){
var to = this.to;
// process message.
to.next(msg); // pass to next middleware
});
});
Registering the in listener via the opt hook lets this middleware become 1st in line (before even gun core), that way you can filter all inputs and reject them if necessary (by not calling to.next(msg)).
Likewise to add headers on the client you would want to register an out listener (similarly to how we did for the in) and modify the outgoing message to have msg.headers = {token: data} and then pass it forward to the next middleware layers (which will probably be websocket/transport hooks) by doing to.next(msg) as well. More docs to come on this as it stabilizes.
Old Answer:
A very late answer, sorry this was not addressed sooner:
The default websocket/ajax adapter allows you to update a headers property that gets passed on every networked message:
gun.opt({
headers: { token: JWT },
});
On the server you can then intercept and reject/authorize requests based on the token:
gun.wsp(server, function(req, res, next){
if('get' === req.method){
return next(req, res);
}
if('put' === req.method){
return res({body: {err: "Permission denied!"}});
}
});
The above example rejects all writes and authorizes all reads, but you would replace this logic with your own rules.

Related

React-redux and React Native error handling for expired JWT

I have a system where the authentication is based around JWT. I have a JWT auth token, and a refresh token on the client. The refresh token is stored in the database on the server, and is used to refresh the JWT once the JWT expires every 12 hours - pretty standard setup I believe.
My issue is incorporating it in to my React Native project and handling token expiration. The user will likely be performing many API calls to their "protected" areas which require the JWT, but once the JWT expires it will send back a "UnauthorizedError" like so:
router.use('/protected', ejwt({secret: config.secret}));
//catch any errors if the JWT is not valid
router.use((err, req, res, next) => {
if (err.name === 'UnauthorizedError') {
res.status(401).send({
success: false,
error: "UnauthorizedError"
});
}
});
This will send back to the RN app that the JWT has expired, but at this point I would like the app to send another request back to the server generate a new JWT, but I'm not sure of a way to do this most efficiently for every API call initiated from my app. Each API call could call a function to check the server if the returned value is "UnauthorizedError", but I know this isn't the best way:
return AuthApi.someApiCall(token).then(response => {
if(response.success){
//do some success stuff
}else{
//this seems bad to be repeated for every API call
checkToken(response).then(() => {
dispatch(updateAuthToken());
});
}
})
I've been looking around and Redux middleware looks promising, but I don't know if there's a more established way perhaps, or anyone has any other thoughts?
Thanks!

ember simple auth session, ember data, and passing a Authorization header

I have a working oauth2 authentication process where I get an access token (eg from facebook) using ember simple auth, send it to the back end which calls fb.me() and then uses JWT to create a token. This token is then sent back to the ember app, which then has to send it with every server request, include those requests made by ember-data.
I also need to have this token available after a browser reload.
I have tried many options, where I set a property 'authToken' on the session - I believe that this uses local storage to persist the authenticated session.
But I always seem to have trouble with coordinating the retrieval of this token - either I don't have access to the session, or the token is no longer on the session, or I can't change the ember data headers.
Does anyone have a working simple example of how this can be done - I think it should be easy, but I'm obviously missing something!
Thanks.
Update
The only thing I've been able to get working is to use torii as shown below, but the session content is still lost on refresh - I can see its still authenticated, but its lost the token I set here. So I'm still looking for a real solution.
authenticateWithGooglePlus: function () {
var self = this;
this.get('session').authenticate('simple-auth-authenticator:torii', 'google-oauth2')
.then(function () {
resolveCodeToToken(self.get('session'), self);
});
}
resolveCodeToToken gets the bearer token from the server, sets it on the session and then transitions to the protected page:
function resolveCodeToToken(session, route) {
var authCode = session.content.authorizationCode;
var type = session.content.provider.split('-')[0];
$.ajax({
url: 'http://localhost:4200/api/1/user/auth/' + type,
data: {authCode: authCode}
}).done(function (response) {
// todo handle invalid cases - where user is denied access eg user is disabled
session.set('authToken', response.token);
route.transitionTo('activity', moment().format('DDMMYYYY'));
});
}
And I have a custom authorizer for putting the token (stored in the session) on every request:
import Base from 'simple-auth/authorizers/base';
export default Base.extend({
authorize: function(jqXHR, requestOptions) {
var accessToken = this.get('session.content.authToken');
if (this.get('session.isAuthenticated') && !Ember.isEmpty(accessToken)) {
jqXHR.setRequestHeader('Authorization', accessToken);
}
}
});
I'm not sure why this.get('session.content.authToken') would be undefined after a refresh, I thought by default the session was persisted in local storage. The fact that it is authenticated is persisted, but thats useless without the token since the server will reject calls to protected endpoints.
You'd want to implement your own custom authenticator that first gets a token from Facebook and then sends that to your own server to exchange it for a token for your app. Once you have that you get authorization of ember-data requests as well as session persistence etc. for free.
Have a look at this example: https://github.com/simplabs/ember-simple-auth/blob/master/examples/7-multiple-external-providers.html

how to use both express.io and passport.socketio authentication features globally

socket.io supports a single global authorization method with no middleware feature. Both express.io and passport.socketio depend on this feature as an injection point for their logic.
express.io attaches the express session to the request, and passport.socketio attaches the inflated user object. how do I combine the two features elegantly?
The only way I found is grabbing the authorization callback of express.io from socket.io and wiring it to be passport.socketio's success callback:
app.io.configure(function() {
var expressAuth = app.io.get('authorization');
var sessionConfig = {
...
success : expressAuth // callback on success
};
app.io.set('authorization', passportSocketIo.authorize(sessionConfig));
});
This works for me, but It's coupled with the order of the 'authorization' registrations. Any better ideas?

What is a good way to implement a custom authentication in Firebase?

I've done some things using firebase (so cool).
I'm doing the custom login, I've generated a AUTH_TOKEN (using nodejs).
My question is if I need to pass in all my page that I wanna to protect the code below?
Peace,
Tulio Cruz
var dataRef = new Firebase("https://example.firebaseio.com");
// Log me in.
dataRef.auth(AUTH_TOKEN, function(error, result) {
if(error) {
console.log("Login Failed!", error);
} else {
console.log('Authenticated successfully with payload:', result.auth);
console.log('Auth expires at:', new Date(result.expires * 1000));
}
});
I'm not sure I fully understand your question. If you want to know if you need to call auth every time a page is loaded -- yes you do. When using custom login with the low-level auth() api call, we don't do any session management for you.
You only need to call auth() once per page load though -- not once for each Firebase reference.

socket.io authentication after socket established

I'm working on a small multiplayer game. I'd like to introduce authentication. I'm using Node.js and Socket.io.
When the user arrives that the main page - I want them to join the game whether they are logged in or not - but they will be unable to do anything within it (only watch).
How could I then go about authenticating the user on the already open socket?
Could I maintain the authentication still if they left the site and came back? Can you pass a cookie through a web socket?
EDIT
To further my question. One of the possible thoughts I've had is to provide the websocket connection, then when they try to login in, it passes username and password as a message to the websocket.
client.on('onLogin', loginfunction);
I could then take the username and password, check against the database, then take the session ID of the socket and pass it somewhere to say that session is authenticated to that user.
Is this secure? Could I still implement a cookie on the socket so they could come back? Is there any way within socket.io of stating that the socket is now authenticated instead of manually checking on each message received?
Cheers
This isn't actually too hard, but you're approaching it the wrong way. A couple things:
You cannot set a cookie with socket.io; you can, however, get the cookie values of any connected client at any time. In order to set a cookie, you will have to send a new http response, meaning the user must first send a new http request (aka refresh or go to a new page, which it sounds is not a possibility for you here).
Yes: socket.io is secure (to the extent that any transmitted data can be).
As such, you can do the following:
On the user's initial connection, create a cookie with a unique session ID, such as those generated from Express's session middleware. You will need to configure these not to expire on session end though (otherwise it will expire as soon as they close their browser).
Next you should create an object to store the cookie session IDs. Each time a new connect.sid cookie is set, store in your new object with a default value of false (meaning that the user has been authenticated by session, but not by logon)
On the user's login, send a socket emit to the server, where you can then authenticate the login credentials, and subsequently update the session id object you created to read true (logged in) for the current socket id.
Now, when receiving a new http request, read the cookie.sid, and check if its value in your object is true.
It should look something like the following:
var express = require('express'),
http = require('http'),
cookie = require('cookie');
var app = express();
var server = http.createServer(app);
var io = require('socket.io').listen(server);
app.use(express.cookieParser());
app.use(express.session({
secret: 'secret_pw',
store: sessionStore,
cookie: {
secure: true,
expires: new Date(Date.now() + 60 * 1000), //setting cookie to not expire on session end
maxAge: 60 * 1000,
key: 'connect.sid'
}
}));
var sessionobj = {}; //This is important; it will contain your connect.sid IDs.
//io.set('authorization'...etc. here to authorize socket connection and ensure legitimacy
app.get("/*", function(req, res, next){
if(sessionobj[req.cookies['connect.sid']]){
if(sessionobj[req.cookies['connect.sid']].login == true){
//Authenticated AND Logged in
}
else{
//authenticated but not logged in
}
}
else{
//not authenticated
}
});
io.sockets.on('connection', function(socket){
sessionobj[cookie.parse(socket.handshake.headers.cookie)['connect.sid'].login = false;
sessionobj[cookie.parse(socket.handshake.headers.cookie)['connect.sid'].socketid = socket.id;
socket.on('login', function(data){
//DB Call, where you authenticate login
//on callback (if login is successful):
sessionobj[cookie.parse(socket.handshake.headers.cookie)['connect.sid']] = true;
});
socket.on('disconnect', function(data){
//any cleanup actions you may want
});
});
Chris, I'm won't be able to answer since I'm not an expert on socket.io, but I can maybe try to point you in another direction that can help you - and take away some development time.
But first, a disclaimer: I work for Realtime.co and am not trying to do any sort of advertising. I work closely with developers and I'm just trying to help you by providing you an out-of-the-box solution for your problem. Also, being a gamer, I can't stay away from trying to help people getting their games out there!
Realtime uses an authentication/authorization layer in which you can provide user read/write permissions to channels. When users enters the website you can give them read only permissions to the game channel and once they login, you can then give them write permissions. This can be easily done by doing an authentication post and reconnecting to the server (it can all be done client side). I would do it server-side, though, to increase security.
Realtime has a Node.js API so you can easily integrate it with your server. Since it also has APIs for many other platforms (including mobile) and they all work the same way, you can actually have your game working in multiple platforms over the same communication layer, while having full control over channels.
Thanks for reading.
Edit:
You can read the documentation here for more info: http://docs.xrtml.org/
Socket.io has an option to pass extraHeaders. One can use that to pass a token from the client. The server would use the desired authentication algorithm to decrypt the token and get the user_id.
socket.js
import io from 'socket.io-client';
export const socket = io('https://remote-url');
export const socketAuth = () => {
socket.io.disconnect(); //This uses the same socket and disconnect with the server.
socket.io.opts.extraHeaders = {
'x-auth-token': JSON.parse(window.localStorage.getItem('auth-token')),
};
socket.io.opts.transportOptions = {
polling: {
extraHeaders: {
'x-auth-token': JSON.parse(window.localStorage.getItem('auth-token')),
},
},
};
socket.io.open(); //Opens up a new connection with `x-auth-token` in headers
};
client.js
import { socket, socketAuth } from 'utils/socket';
socket.on('unauthenticated-messages', () => {
someAction();
});
//After user logs in successfully
socketAuth();
socket.on('authenticated-messages', () => {
someAction();
});