How is this actually done? - node.js

I am doing a project with authentication using passport js with the Strategies (Google, Facebook, Local). I am working on the google part now but there is a small problem. When users register locally I save their data to the db (email,username,hashedPassword) but now when they register/signin through google I do not have access to their password (obviously). It is required in the user schema and I do not want to create a new user schema.
Could I save the password as the user id I received from google? I really want to know the correct path I should take.

You could add another field to your schema like provider that specifies the type of authentication that was used. Then you can use the mongoose required validator to make password only required if provider is 'local.' Something like this:
const userSchema= new Schema({
firstName: String,
lastName: String,
email: String,
username: String,
provider: {
type: String,
enum: ['local', 'google', 'facebook']
},
password: {
type: String,
required: function() {
return this.provider === 'local';
}
}
});

When you go use an auth provider, they usually will give you some sort of "token", maybe on your client or on a redirect on your server (depends on your implementation).
Then you have to validate that token with the provider (how to do this depends on the documentation of each provider), because you can not plain trust that a given token is valid.
Once you have validated with the provider that the token is valid, is common that with that token you have access to some info of the user, like email, name, phone number, etc (depends on how you configure your integration) and maybe store which provider they use (fb, google, apple, etc)
Then you can save this information in your schema, and then generate a session for this user (it may be a JWT or a session stored on the db)
Now, when a user sign in, you will do the same validation process of the given token with the user sent, then you can provide a new session
In summary, the key is that instead of using user/pwd to validate against your local database to authenticate a user, they will provide a token, and you have to validate that token against the provider they selected

Related

Generate API keys with JWT and regenerate the same key when needed

I recently found my self in need of developing a public API for my application. I developed my application with node.js and mongodb. After some research, I decided to use jwt for generating API keys for users and authentication. For authenticating jwt tokens, they come with the benefit of not needing to store them in a database, as they can be decoded and verified without knowing the exact generated token.
But I see that lots of applications show the users their API keys in the application dashboard, so I need to actually store the token in order to show them to the users later on. I know that storing tokens is a bad idea and in case of a database breach, it could let the hackers impersonate others with the API keys.
So long story short I am trying to find a way to not to store the exact tokens, but store only the payload in the database and every time users request their API keys I just generate the same one with a SECRET and pass it to them. I currently find that if on the signing token step, I pass the same payload with the same iat (issued at) every time, the generated token will be the same every time. So by saving the iat with the payload data in the database, I can generate the exact token every time.
Here is my mongoose schema:
var KeySchema = new mongoose.Schema({
name: { type: String, default: 'API Key' },
active: { type: Boolean, default: true },
iat: { type: Date, required: true },
project: { type: mongoose.Schema.Types.ObjectId, ref: 'Project', required: true },
});
And this is how I generate the same token with jsonwebtoken npm package:
import jwt from 'jsonwebtoken';
jwt.sign({ project, iat: CONST_TIMESTAMP }, config.secrets.session);
Now my questions are:
Does this approach is a good approach or is there a better way to achieve this?
Is there any good practice for generating API keys without storing them?
Does this even necessary (considering if there ever be any database beach, all of the data is already stolen)?
Is there any method other than using jwt to achieve this?
JWT is a standard approach for the given objective and for you I would recommend to use asymmetric signing key.
The advantage of this would be the consumers or clients will need to trust the issuer and there are multiple ways in which the public part of the key can be distributed.
So this does away with the requirement of key regeneration , also you can use the standard techniques for securing the private part of the signing key.

passwordHash field in admin.auth.UserRecord interface of Firebase Admin SDK

I'm trying to get the hashed passwords of my users using Firebase Admin SDK.
From the documentation,
Optional passwordHash
passwordHash: string
The user’s hashed password (base64-encoded), only if Firebase Auth hashing algorithm (SCRYPT) is used. If a different hashing algorithm had been used when uploading this user, as is typical when migrating from another Auth system, this will be an empty string. If no password is set, this is null. This is only available when the user is obtained from listUsers().
But after retrieving a UserRecord object, the passwordHash property is always set to 'UkVEQUNURUQ=', irrespective of that user's password.
Users are created in the backend using the admin SDK like so
admin.auth().createUser({
uid: uid,
email: email,
phoneNumber: phoneNumber,
password: password
})
Why are the hashes all the same?
Apparently, this is a known bug.

managing user sessions for multiple devices node js using JWT

I am making an application in which I am using JWT for maintaining sessions. When any new user registers then I provide a JWT token to user and store it in my database as well as in users browser. When user log out, then i delete that token from browser and my database.
But I want that if user is logged in from multiple devices then it it will log out from one device, it does not logout from other devices as well. How do I achieve this?
First, JWT are not supposed to be able to "log out", but to automatically expire, that is why you are supposed to set short expiresIn times.
It is because with JWT, sessions are handled by the client, it is not the server's responsibility to log out users, it is the user who just throw away the JWT.
In your case, I suppose you check if the JWT exist in your DB before allowing the user, and as such, you just need to search and delete the others JWT associated to that account.
But if you want to make things clean, embrace JWT logic: just set short life time, and wait for them to expire.
Just use an array of tokens in database. Each device will have it's own token in the array of tokens (each token was added to db when user first logged in from a new device) and when the user logs out from that device, only the associated token from the tokens array gets deleted. Here is an example of User schema:
var userSchema = new mongoose.Schema(
{
name: {
type: String,
require: true,
trim: true
},
.
.
.
tokens: [
{
token: {
type: String,
required: true
}
}
],
{
timestamps: true
}
);

Passport Authentication - Any?

I am writing a nodejs application with passport.js-based authentication. It lets users message other users, where only authenticated users are allowed to retriever messages either sent by them or with them as the receiver. I am planning to implement multiple identity providers, such as facebook, google, and maybe local authentication as well.
The user schema i set up using mongoose looks like sort of like this:
var userSchema = new mongoose.Schema({
googleId: String,
facebookId: String,
email: { type: String, required: true },
}, {
strict: false
})
module.exports = mongoose.Model('User', userSchema)
Now the approach I had in mind was this:
A user is presented a sign in page
On this page they are presented a choice of identity providers
They get redirected to authorization page, granting access to the requested scopes, getting redirected to my specified callback URL
There is either already a user with the according ID or a new one is created.
Now when they try to receive the message, I want to authenticate them again in order to grant authorization to obtain the message. How they authenticate really does not matter, as long as it is any of the strategies I configured; there is however no such thing as app.get('/messages', passport.authenticate('any'), done), so how would I approach this?
One option is to pass the strategies you want as an array into passport.authenticate([Strategies]). The link below shows that nicely.
passport.js with multiple authentication providers?
Another example from the author of passport:
https://github.com/jaredhanson/passport-http/blob/master/examples/multi/app.js

Should user object be stored in JSON Web Token?

My question is rather simple should we or should we not store a user object in the JWT's payload?
For example:
WIth user object embedded:
{
iss: "https://YOUR_NAMESPACE",
user: user, // user object from database
aud: "YOUR_CLIENT_ID",
exp: 1372674336,
iat: 1372638336
}
Or is it better to store only a unique id of a user, like so:
With just the user id embedded:
{
iss: "https://YOUR_NAMESPACE",
sub: user.id, //only user id
aud: "YOUR_CLIENT_ID",
exp: 1372674336,
iat: 1372638336
}
JSON Web Token Draft Spec: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-json-web-token
You can store any kind of information about the user in your token, but I do not think it is useful to store all user informations.
As HTTP is stateless, each time a user connects on your website or web app, the token is sent to the server to authenticate the user. So this token should be as small as possible (that is the aim of the JSON Compact Serialization format of JWT).
You should store an unique information to identify the user such as its email address or its ID (aud: "YOUR_CLIENT_ID").
When needed, you can request informations about the user to the server using API calls or any other protocol.

Resources