Determining How To Authorize with NodeJS/Mongoose - node.js

I am working on a NodeJS/express application using passportJS for sign in/sign up. I have defined a user model for all users, but want only certain users within my administration to have access to editing certain models. I was thinking of adding a boolean field, like isAdmin to determine this, but I don't know how I would verify admin users. To be specific, how would I determine when I need to generate a token for the admin user? How do I differentiate users in my administrations from ordinary users? I was thinking of having a separate locally hosted website that connects to the same database that I could use to manage models only from my computer. Would that work?
Any help would be greatly appreciated!
Thanks!

There are many option available. i can explain you some of them.
1) As you said you can define boolean field as is Admin true of false.
-> if you are using this option and you are using passport. You must get user in your request object.Before hitting api or particular endpoint you can set middleware to verify that requested user is admin or user.
file
Filename : ../services/auth.service.js
exports.isAdmin = async (req, res, next) => {
// req.user is object that you will get after successfull login. change accordingly
// Or you can check from db also. Get object logged in user from db by their email id.
// And check condition
// Check Role if admin or not
if(req.user.isAdmin) {
next(); // If verify it will redirect to next process
} else {
return res.status(401).json({
Error: true,
message: 'You are not authorized to perform this action.',
})
}
};
You can use this function as middleware.
const auth = require('../services/auth.service.js')
router.get('/*', auth.isAdmin, (req, res) => {
res.status(200).json({ message: "Hello from Admin side."})
});
Visit : https://github.com/mihir-kanzariya/Nodejs-CRUD

Related

Get Windows username(frontend) in nodejs to use my own authentication system

I developed a webapp using React and NodeJS to manage a database in an intranet. Now, in order to grant access to each user, I want to use the windows username to authenticate them.
I have tried node-expose-sspi, it gives me the username but also authenticate users. There is any option to oly get the username and use my own authentication system?
const { sso } = require('node-expose-sspi');
app.use(sso.auth()); ----> **This line is causing my fetches from React dont work.**
app.use('/myauth', (req, res, next) => {
res.json({
sso: req.sso,
});
});
when geting the route mywebapp:5000/myauth -> It display the username. But my my fetches form react are not successful

firebase.auth().currentUser returning null

In the html file that I have for the sign-in page, I perform the authentication using Firebase and on successful authentication, I redirect the given user to the homepage. When I call firebase.auth().currentUser in the express file, I use for rendering and routing pages, I get undefined or null for the current user.
Can anyone help me understand what the issue might be?
This is how I perform the authentication:
firebase
.auth()
.signInWithEmailAndPassword(temail, tpass)
.then(function(firebaseUser) {
window.location.href = "http://localhost:5000/homepage";
})
.catch(function(error) {
window.alert("incorrect pass");
});
This is the code that I have in my express file:
app.get("/homepage", (req, res) => {
var user = firebase.auth().currentUser;
console.log("USER IS " + user);
res.render("menu", { title: "Welcome" });
});
Backend code doesn't have a sense of "current user". When you sign in on the frontend, the current user is only known on that client. It isn't known on the backend. If you want the backend to know which user is signed in, the client will have to send an ID token to the backend for it to verify. The documentation for the Firebase Admin SDK is used for that on the backend. The client must send the ID token to in the request to your route, and the code handling that route must verify the token in order to know the user that made the request. From the documentation:
If your Firebase client app communicates with a custom backend server, you might need to identify the currently signed-in user on that server. To do so securely, after a successful sign-in, send the user's ID token to your server using HTTPS. Then, on the server, verify the integrity and authenticity of the ID token and retrieve the uid from it. You can use the uid transmitted in this way to securely identify the currently signed-in user on your server.
When the user lands on a new page, Firebase automatically restores their previous authentication state. But to do so, it may have to contact the server, which means that it may take a few moments. While Firebase is restoring the state, auth().currentUser will be null.
To ensure you get the correct authentication state, you should use an authentication state listener, as shown in the documentation on getting the current user:
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
});

how to verify a firebase admin on backend

I'm trying to implement middleware in an express server that sets custom uid/admin headers on the incoming request. This modified request will then be used after the middleware to see if an authenticated user/admin is accessing that particular resource.
To do this for a client, I just grab the token on the Authorization header and feed it into the firebase admin api's verifyIdToken method. If a uid exists, I set the header. For example:
app.use((req, res, next) => {
/* get rid of headers sent in by malicious users. */
delete req.headers._uid;
try {
const token = req.headers.authorization.split(' ')[1];
_dps.fb_admin.auth().verifyIdToken(token).then(claims => {
if (claims.uid) { req.headers._uid = claims.uid; }
next();
}).catch(err => next());
} catch(err) { next(); }
});
Two questions:
1) As an admin with a service account on another server, how would I send a request to this server such that this server can determine an admin sent the request?
2) How would I identify the admin on this server?
You will need to create your own custom Firebase token to include custom fields such as isAdmin: true in the JWT. See https://firebase.google.com/docs/auth/admin/create-custom-tokens
See (1)
Use the setCustomUserClaims() API to add a special "admin" claim to all admin user accounts, and check for it when verifying ID tokens. You can find a discussion and a demo of this use case here (jump ahead to the 6:45 mark of the recording).
Perhaps a solution would be to simply generate an API key of decent length and set it as an environment variable on each of my servers. I could then send this in the Authorization header whenever i want to make an admin https request and verify it in the middleware of the receiver by doing a simple string compare. The only people that could see this API key are those that have access to my servers (AKA admins). Let me know if something is wrong with this approach. It sure seems simple.

Using AWS Amplify to authenticate Google Sign In - federatedSignin returns null?

I'm trying to use AWS Amplify to support email / password and Google authentication. Now, I want to store the details from Google into my user pool in AWS. I don't understand the flow here - there are many blog posts I read but most of them are just confusing.
Here's what I tried to do:
// gapi and Amplify included
googleSigninCallback(googleUser => {
const googleResponse = googleUser.getAuthResponse();
const profile = googleUser.getBasicProfile();
const name = profile.getName();
const email = profile.getEmail();
Amplify.Auth.federatedSignin('google', googleResponse, {email, name})
.then(response => { console.log(response); }) // is always null
.catch(err => console.log(err));
});
In DevTools I have the following error in the request in Network Tab:
{"__type":"NotAuthorizedException","message":"Unauthenticated access
is not supported for this identity pool."}
Why should I enable unauthenticated access to this pool? I don't want to.
Am I doing this right? Is it even possible or is it a good practice to store Google User details into the AWS User Pool? If it's not a good practice, then what is?
Also, if I want to ask user for further details not provided by Google in the app and store them, how to do it if we can't store the user in User Pool?
First make sure your identity pool and user pool are setup for google authentication.
Then federatedSignIn has a capital last I.
And finally just change your second param in the call to federatedSignIn as follows:
Amplify.Auth.federatedSignIn('google', {
token: googleResponse.id_token,
expires_at: googleResponse.expires_at
}, {email, name})...

Passport authentication not working in sails.js application

I have a Sails JS application. I am trying to setup authentication using Passport.js authentication layer sails-generate-auth. I have configured my app by following the steps given in their documentation.
But when I lift my sails app, authentication is not working. I am able to access the controllers, even when I am not logged in (It's not redirecting to my login page).
I added a console.log statement in api/policies/passport.js as follows:
module.exports = function (req, res, next) {
passport.initialize()(req, res, function () {
passport.session()(req, res, function () {
res.locals.user = req.user;
console.log(req.user); // added by me
next();
});
});
};
Now, when I access controllers before login or after logout, its printing undefined. But when I am logged in, its printing my user data. Any idea why it is not checking for authentication?
I am using local authentication strategy and I have commented out all others (twitter, facebook...)
The above answer provides useful information. I want to elaborare on that.
sails-generate-auth, by default doesn't deny access to controllers if the user is not logged in. For that, you can create another policy in api/policies/. For example: create sessionAuth policy as follows:
module.exports = function(req, res, next) {
if (req.user) {
return next();
}
return res.forbidden('You are not permitted to perform this action.');
};
Instead of showing forbidden page, you can also render login page. For that you need access to AuthController.login. So, add the policies in config/policies as follows:
'*': ['passport', 'sessionAuth'],
'auth': {
'*': ['passport']
}
This helps to restrict access all the controllers except auth controllers such as login, logout and register, if the user is not logged in.
Passport doesn't have a policy to deny access to a controller. For this, you have to create another policy.
See this link for more details.

Resources