socket.io unity authentication - authentication

I have this use case:
- I'm working on a game with a webapp for user management and chat, which is on MERN, and a unity game, with socket.io as the real time messaging layer for the multiplayer game.
- User may register to webapp by either providing a pair of email/password, or getting authenticated on FB/Gamil/etc. as usual, in which case the user's email is obtained and saved to MongoDB and this is done by passport.
- There is no session in express side, and socket.io is on a redis. There is no cookie but JWT is used.
My problem is that I don't know what's the best practices in this. I read this
article
and this
one
which both have content and code close to what I want to do, but in the first one:
app.use(express.cookieParser());
while I don't want to use cookie at all, and the other one also has in code:
cookie: {
secure: process.env.ENVIRONMENT !== 'development' && process.env.ENVIRONMENT !== 'test',maxAge: 2419200000}...
Also, I found this on
github
which suggests for the client side (unity):
var socket = io.connect('http://localhost:9000');
socket.on('connect', function (socket) {
socket.on('authenticated', function () {
//do other things
})
.emit('authenticate', {token: jwt}); //send the jwt
});
meaning that:
1. socket is created
2. authentication is requested
but I think that the approach I found in the other article is better, where the socket is not created at all if the JWT for auth is not provided at the first ever connection request sent to "io", so if I'd do it I'd issue:
var socket = io.connect('http://localhost:9000', {query: {"JWT":"myjwt"}});
and in my server side where I have:
io.on("connection", function(socket){...});
I'd like to first get the JWT:
var jwt = socket.handshake.query["JWT"];
and then if auth will be unsuccessful, simply return socket.disconnect('reason') and do not open any connection at all (here maybe I just didn't understand, say, that the approach the Author took in the github source is using a middle ware technique and it is maybe also done before anything else).
I still could not find out what is the best practice that Gurus use, please help me get clear.

Related

What's behind a REST API

I'm working on the frontend part of some REST API (link, json validation and in generale controlling)
I'm trying to figure out how it works in the backhand, there should be a database I guess and each API call correspond to a specific query?
could you suggest me guide on how such implementation are usually build?
I'm only finding formal guide on how to shape url for rest API
thanks
It is a quite generale / cultural question, not technical
There's no standard way, the point of a protocol like HTTP (what REST is based on) is to decouple this kind of details and leave the server implementor to be free of doing it however it wants.
There are a lot of different ways and listing them all is very hard.
For a simple service what you said is true, for more complex scenario behind a REST endpoint there could be a service doing calls to other services and aggregating their responses into the json you see.
You would usually have a single endpoint do a single task but you could also do anything you want with the data provided from the user. You could carry out regex validations, store it inside a database, send it to another API, extract data out of it, and plenty of other things.
Here is an example I wrote in Node.js:
const signup_post = async (req, res) => {
const { email, password, username } = req.body;
try {
const user = await User.create({ email, password, username });
const token = createToken(user._id);
res.cookie('jwt', token, { httpOnly: true, maxAge: maxAge * 1000 });
res.status(201).json({ user: user._id });
}
catch(err) {
const errors = handleErrors(err);
res.status(400).json({ errors });
}
}
This example code, we are taking the user-provided data, making a new entry in the database with a pre-defined schema, creating a JWT token and attaching it to a cookie, and sending the cookie back to the client. This is one way to handle authentication- and as long as the client has this cookie, they will stay logged in.
We are also handling any errors and validating the user-provided data to make sure it fits our database schema.

How to change the http client used by pouchDB?

I am using PouchDB and CouchDB in an ionic application. While I can successfully sync local and remote databases on Chrome and Android, I get unauthorized error on Safari / iOS when I run the sync command. Below is a simplified version of my database service provider.
import PouchDB from 'pouchdb';
import PouchDBAuthentication from 'pouchdb-authentication';
#Injectable()
export class CouchDbServiceProvider {
private db: any;
private remote: any;
constructor() {
PouchDB.plugin(PouchDBAuthentication);
this.db = new PouchDB('localdb', {skip_setup: true});
}
...
login(credentials) {
let couchDBurl = 'URL of my couchDB database';
this.remote = new PouchDB(couchDBurl);
this.remote.logIn(credentials.username, credentials.password, function (err, response) {
if (err) { concole.log('login error') }
else {
let options = { live: true, retry: true, continuous: true };
this.db.sync(this.remote, options).on('error', (err_) => { console.log('sync error')});
}
})
}
...
}
In the code above, this.remote.logIn(...) is successful but this.db.sync(...) fails. I have checked the requests via the network tab of developer tools and I believe the issue is that the cookie that's retruned in the response header of this.remote.logIn(...) is not used by the subsequent calls (thus the unauthorized error). The issue is fixed once third-party cookies are enabled on Safari, which is not an option on iOS.
How can I fix this problem?
One potential solution I'm considering is overriding fetch to use native http client (i.e., an instance of HTTP from #ionic-native/http). It seems modifying http clients is a possibility (e.g., according to this conversation) but I'm not sure how to achieve that.
Changing the HTTP plumbing sounds like a really bad idea - time cost, mainly - unless you just absolutely have to use sessions/cookies...If you don't, read on.
as noted here regarding pouchDB Security, I tried using pouchdb-authentication when it was actively maintained and went another route due to multiple issues (I don't recall specifics, it was 6 years ago).
Do note the last commit to pouchdb-authentication seems to be 3 years ago. Although inactivity is not an negative indicator on the surface - a project may have simply reached a solid conclusion - installing pouchdb-authentication yields this
found 6 vulnerabilities (2 moderate, 3 high, 1 critical)
That plus the lack of love given to plugin over the last few years makes for a dangerous technical debt to add for a new project.
If possible simply send credentials using the auth option when creating (or opening) a remote database, e.g.
const credentials = { username: 'foo', passwd: 'bar' };
this.remote = new PouchDB(couchDBurl, { auth: credentials });
I don't recall why but I wrote code that is in essence what follows below, and have reused it ad nauseum because it just works with the fetch option
const user = { name: 'foo', pass: 'bar' };
const options = { fetch: function (url, opts) {
opts.headers.set('Authorization', 'Basic ' + window.btoa(user.name+':'+user.pass));
return PouchDB.fetch(url, opts);
}
};
this.remote = new PouchDB(couchDBurl, options);
I believe I chose this approach due to the nature of my authentication workflow discussed in the first link of this answer.
I agree with #RamblinRose that you might have to include the headers manually when you define the PouchDB object.
I myself have found a solution when working with JWTs that need to be included in the header for sync purposes.
See this answer. Note: RxDB uses PouchDB under the hood so it's applicable to this situation. It helped me sync, hope it does you too!
https://stackoverflow.com/a/64503760/5012227
One potential solution I'm considering is overriding fetch to use native http client (i.e., an instance of HTTP from #ionic-native/http). It seems modifying http clients is a possibility (e.g., according to this conversation) but I'm not sure how to achieve that.
Yes, this is a possible option - especially if you want to use SSL pinning which will only work with native requests. And you don't need to worry about CORS (apart from ionic serve).
You can achieve this e.g. by taking an existing fetch - polyfill and modifying it s.t. it uses the http plugin instead of xhr. And since you'll only deal with JSON when interacting with the CouchDB, you can throw away most of the polyfill.

What is the point of this "token" in IndexedDB firebase-messaging-store

I am confused, Can i use this token (stored in indexedDb) for subscribe the device to topics or sending push notifications to device ?
What is the point of this token ?
Best Regards
Thanks
Most likely this database is how the Firebase Cloud Messaging client stores the device token. This is however not documented, so you should not rely on this database entry existing.
Instead, if you want to use the token (to subscribe to a topic or for another cause) use the public API to get the token:
messaging.getToken().then((currentToken) => {
...
});
The above may read the token from the indexeddb, but it may also actively get the token from a call to the FCM servers.
As Frank said,
const localStorageKey = 'webpush';
messaging.getToken().then((currentToken) => {
if (localStorage.getItem(localStorageKey) !== currentToken) {
localStorage.setItem(localStorageKey, currentToken);
}
...
});
Firebase stores token in indexed db. When the token refresh IndexedDb will take the updated token.
Theese tokens are exactly same.
My token changes because my service worker unregister on every page refresh (in dev. mode it is weird). Then it registering again. So, if service worker status is unregistered firebase going to create new token. But in production mode service workers work well.

Incorporating sendEmailVerification method in frontend handler or backend signup method?

I'm trying to incorporate an email verification step in the signing up process of my app. Looking at the docs online, seems like doing it in the front-end seems like the way to go.
Problem is the examples I see online have the entire sign in process done in the front-end, and just simply include the the sendEmailVerification method.
sendEmailVerification Method
firebase.auth().currentUser.sendEmailVerification().then(function() {
// Email sent.
}).catch(function(error) {
// An error happened.
});
I (instead) built my sign up method in the backend and its respective handler in the front.
Front-End Sign Up Handler
authHandler = () => {
const authData = {
email: this.state.controls.email.value,
password: this.state.controls.password.value
};
this.props.onTryAuth(authData, this.state.authMode);
// ontTryAuth is a backend action that creates new users in Firebase
};
Is it a good idea to include the sendEmailVerification method into this front-end handler code? If so, how do I go about doing it?
Yes you can use it. First this method is built by Firebase because people who use Firebase don't always/never have a server. You can yes build your own signup method in your server, but why you would use Firebase if you start to override all the stuff they give you? For me I see Firebase as a prototyping tool and so I use all the features they give, so that let me put an app working faster.
Let me know if that make sense.

Auth0: Validating id_token/JWT on UI (javascript) level

Update March 2019
I just went over this question again; the Auth0's github code has been updated in December 2018. They are now storing 'access_token','id_token' and 'expire_at' into the object/session, instead of localstorage and using now an 'isLoggedIn' flag to mark if authenticated or not. Check the pull request and these 2 lines in the specific commit: line1 and line2.
If you do not need to re-validate 'id_token' - like I was doing in the original question - that might be an alternative. Otherwise check original question.
Original Question
We are using auth0 for one of our clients. One stack that we are using it for is:
React/Redux UI
NodeJS backend
So we are using a cross origin authentication using implicit grant for that, using JWT with an RS256 algorithm. We also refresh tokens in background using silent authentication.
I was able to validate 'access_token' on the API (nodejs) side using node-jwks-rsa for express
On the UI level, after going through the source code of the auth0-js library I noticed that the "parseHash" method used in their provided react samples, actually validates tokens before we store them in localstorage, ie on successful authentication. Mainly this line in the source code.
Then I used their sample code that allows us to check if a user is authenticated, method isAuthenticated().
Problem with the isAuthenticated() method
From a security perspective, if later on (post authentication) a user of the application decided to manually modify the 'expire_at' label in the storage, they could get away as indeed authenticated. While of course there is additional security checking in our app, I wanted to update this function to validate 'id_token'. So far, I couldn't find any example in auth0's online docs for how to do that.
After digging in their source code I found a method validateToken that is being used. So I decided to leverage it in one of our functions:
import IdTokenVerifier from 'idtoken-verifier'
.... Some code in here ....
reValidateToken() {
return new Promise((resolve, reject) => {
// Both of these are stored in localstorage on successful authentication, using the parseHash method
let id_token = localStorage.getItem('id_token');
let transactionNonce = localStorage.getItem('app_nonce');
this.webAuth.validateToken(id_token, transactionNonce, function(
validationError,
payload
) {
if (!validationError) {
resolve('no validation errors for id_token');
}
if (validationError.error !== 'invalid_token') {
reject(validationError.error);
}
// if it's an invalid_token error, decode the token
var decodedToken = new IdTokenVerifier().decode(id_token);
// if the alg is not HS256, return the raw error
if (decodedToken.header.alg !== 'HS256') {
reject(validationError);
}
});
});
}`
Now, for it to succeed; we store the nonce in localstorage after successful authentication, does this approach create back doors for potential security holes? if it does; what is best practice to validate RS256 JWT id_token(s) on a UI level?