How to verify user using Angular JS and JWT? - javascript

I am currently working on registration module. I am able to register using a form. I am using Angular JS for frontend and Nodejs for backend services. I call the API and thus it gets registered. After registering, the user gets a verification mail upon which clicking the button, the user should be successfully verified.
I have achieved till sending a mail but after clicking on 'verify button' in mail it lands onto login page directly without verifying. I want to verify the user and send the token to the verify API. I am not sure about how to go about it.

Use node jwt module which solve your problem.
When user login then create token for user
var token = jwt.sign(user, app.get('superSecret'), {
expiresIn: '1440m' // expires in 24 hours
});
Then sent token with response each time when user try to access any url create middle-ware that will verify user token it is valid or not.
/* Middle-ware to verify toke */
apiRoutes.use(function(req, res, next) {
// check header or url parameters or post parameters for token
var token = req.body.token || req.query.token || req.headers['x- access-token'];
// decode token
if (token) {
// verifies secret and checks exp
jwt.verify(token, app.get('superSecret'), function(err, decoded) {
if (err) {
return res.json({ status: 102, message: 'Failed to authenticate token.' });
} else {
// if everything is good, save to request for use in other routes
req.decoded = decoded;
next();
}
});
} else {
// if there is no token
// return an error
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
});

Related

node js backend security header

im trying to make a login endpoint/api, and i am sending the user login data through the authentication headers, is that okay for the security?
the authorization headers is actually contains an object, it is encoded to a Base64, it contains user data like hashed password (not hashed yet in this code), username, and some sort of a serverkey (to authorize if it is the right client that sending an api request), just wanna make sure if it is secure or not..
const aFunction = (req, res) => {
require('crypto').randomBytes(48, function(err, buffer) {
const token = buffer.toString('hex');
const auth = JSON.parse(Buffer.from(req.headers.authorization, 'base64').toString('ascii'))
if(auth.serverkey == version["serverkey"]){
loginUser(auth.username,token).then(data =>{
if (data.rows.length < 1 || data.rows[0].password != auth.password) {
res.send({
status: "failed",
message: "Username/Password is wrong",
status_code: 400
})
}else{
res.send({
status: "success",
message: "successfully logged in",
status_code: 200, token: token
})
}
})
}else{
res.send({
status: "failed",
message: "Unauthorized Client",
status_code: 401
})
}
});
}
I would add a check for if (req.secure) to your code, and reject any non-https request coming your way. (Don't do this if your nodejs program is behind a reverse proxy.)
Users with browsers can see everything you send back and forth to your server, whether via https or http. (devtools) So, if by reading your headers they can figure out how to send you malicious headers, then somebody will. And base64 encoding has exactly the same security as no encoding at all. So salt and hash your passwords. Use the bcrypt package or jwts.
I would handle errors this way, by calling next() with an error parameter rather than by using .send() to deliver a failure message. Use this sort of code.
const createError = require('http-errors')
...
const myfunction (req, res, next) {
...
if (!req.secure) return next(createError(403, 'https required'))
...
});

Using the Google Sign-In bearer token on vanilla javascript web app hosted with firebase functions

It seems there are many issues surrounding this with very few results e.g. here with no definitive answer.
Using the javascript Google Sign-in method, which returns the OAuth credential which includes accessToken, User, etc - the token which should be present in all authenticated requests to the hosted app (where security is crucial).
Is the following a good solution for vanilla Javascript web apps client-side (in one of the .js files) and what issues may arise from it?
// 1. Sign-in
firebase.auth()
.signInWithPopup(provider)
.then((result) => {
// 2. upon successful sign-in
Axios({
url: "/user/register-token",
method: "POST",
headers: {authorization: `Bearer ${idToken}`},
data: { //empty }
}).then((result) => {
// 3. successfully registered & authenticated, proceed to authenticated dashboard route
window.location.assign('/user/dashboard');
}).catch((error) => { // handle error});
}).catch((error) => {
// 4. Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
console.log(error);
});
Steps:
Sign-in with Google signin (using popup)
On successful popup signin, send token to GET /user/register-token which takes the token, verifies it (with some additional email domain checks) and saves it to the session cookie
Upon successful token registered, go to authenticated page
Handle error
My logic:
Since the session is stored server side, but there are session Id's attached to the current browsing session, I can thus use this as a "password of sorts" to verify the firebase session.
Concerns:
The only concern is using any verified firebase token and registering it. This however is address (where I check the associated email and confirm it is part of a firebase user collection & it has a recognized and accepted domain). Thus, they are not confirmed and sent back to the login page with a HTTP/403.
Is my logic sound, are there any potential issues?
My solution was on the right track, and matched up quite well with Firebase's cookie session.
For the record, I had alot of trouble storing the bearer token in my express session, thus searched for other solutions.
According to my steps, the solutions follows the same footprint, but with a slightly different implementation:
client-side changes
The ID Token (bane of my existence for atleast 24 hours) can be retrieved using this solution.
TL;DR (client side)
firebase.auth()
.signInWithPopup(provider)
.then((result) => {
firebase.auth().currentUser
.getIdToken()
.then((idToken) => // use this idToken, NOT result.credential.idToken
//...
Finally, send that to your server to create a session, endpoint is of your choosing e.g. POST: /user/createSession
Server-side changes
You need an endpoint (mine is /user/sessionLogin - part of userRouter - see more more info). Using the code below, you can also include CSRF (I couldn't get mind to work on the client side...), createSessionCookie using the idToken above - this works perfectly w/o any issues.
router.post('/sessionLogin', (req, res) => {
// Get the ID token passed and the CSRF token.
const idToken = req.body.idToken.toString();
// const csrfToken = req.body.csrfToken.toString();
// // Guard against CSRF attacks.
// if (csrfToken !== req.cookies.csrfToken) {
// res.status(401).send('UNAUTHORIZED REQUEST!');
// return;
// }
// Set session expiration to 5 days.
const expiresIn = 60 * 60 * 24 * 5 * 1000;
// Create the session cookie. This will also verify the ID token in the process.
// The session cookie will have the same claims as the ID token.
// To only allow session cookie setting on recent sign-in, auth_time in ID token
// can be checked to ensure user was recently signed in before creating a session cookie.
const auth = admin.auth();
auth.verifyIdToken(idToken).then(value => {
console.log("Token verified")
return auth.createSessionCookie(idToken, {expiresIn})
.then((sessionCookie) => {
// Set cookie policy for session cookie.
const options = {maxAge: expiresIn, httpOnly: true, secure: true};
res.cookie('session', sessionCookie, options);
res.end(JSON.stringify({status: 'success'}));
}).catch((error) => {
console.error(error);
res.status(401).send('UNAUTHORIZED REQUEST!');
});
}).catch(reason => {
console.error("Unable to verify token");
console.error(reason);
res.status(401).send('INVALID TOKEN!');
});
});
Finally, to validate your requests and check cookie status, you need to verify your requests to the server using (or request a new login session by redirecting to /user/login):
exports.authenticate = (req, res, next) => {
const sessionCookie = req.cookies.session || '';
// Verify the session cookie. In this case an additional check is added to detect
// if the user's Firebase session was revoked, user deleted/disabled, etc.
return admin
.auth()
.verifySessionCookie(sessionCookie, true /** checkRevoked */)
.then((decodedClaims) => {
req.user = decodedClaims;
next();
})
.catch((error) => {
console.error(error);
// Session cookie is unavailable or invalid. Force user to login.
req.flash("message", [{
status: false,
message: "Invalid session, please login again!"
}])
res.redirect('/user/login');
});
};
see this for more information.

How can I get AWS credentials using a SAML token?

What I am trying to do: Authenticate my users using ADFS, pass the SAML response token to AWS and get back credentials which I can then use to access AWS resources.
What I am able to do now: Sign in successfully through ADFS and get the SAML token back which confirms the successfully sign in.
What is not working: Calling the AWS.STS.assumeRoleWithSaml functions gets a 403 Access Denied error
How it works thus far:
Users click a button on my application, which calls the following:
var RPID = encodeURIComponent('urn:amazon:webservices');
var result = 'https://virtualMachine.eastus.cloudapp.azure.com/adfs/ls/IdpInitiatedSignOn.aspx?loginToRp=' + RPID;
window.location.href = result;
A successful sign in here returns back to the application a SAML response token
var saml = new URL(window.location.href);
var token = saml.searchParams.get('SAMLResponse');
The application then calls assumeRoleWithSAML to get back credentials. The Principal ARN refers to the identity provider I am trying to access and the RoleARN refers to a role which has full access to everything:
authenticateSAMLwithCognito(token) {
//define our security token service object
var sts = new AWS.STS();
//build our parameter object
var params = {
//cognito identity provider
PrincipalArn: 'arn:aws:iam::accountid:saml-provider/wmpo-adfs',
//role assuming
RoleArn: 'arn:aws:iam::accountid:role/ADFS-Dev',
//authorization
SAMLAssertion: token
}
console.log("Parameters sent", params);
sts.assumeRoleWithSAML(params, (err, data) => {
if(err) console.log(err);
else console.log("Success!", data);
})
}
However the response from this exchange is:
I am really unsure why this is, but if anyone has some helpful pushes that would be great! Thanks and happy new year
Wow that only took days, but though I was constantly stumbling, I finally made it to the point I was trying to get.
The answer was in the same credentials get function that I used when I authenticated users through a username password combo by way of a Cognito User Pool.
authenticateThroughCognito(token) {
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'us-west-2:IdentityPoolId',
Logins: {
'arn:aws:iam::accountId:saml-provider/wmpo-adfs' : token
}
});
(AWS.config.credentials as AWS.Credentials).get((err) => {
if(err) console.log(err);
else {
console.log("Success");
console.log(AWS.config.credentials);
}
})
}

Firebase admin sdk: idToken OR custom token verification for authorization

I'm creating a custom token on backend server while login and below is the code:
UserSchema.methods.generateAuthToken = function() {
var user = this;
var access = "auth";
return firebaseAdmin.default
.auth()
.createCustomToken(user._id.toHexString())
.then(function(token) {
user.tokens = user.tokens.concat([{ access, token }]);
return user.save().then(() => {
return token;
});
});
};
and storing this token inside mongodb and sending it back to client via header named "x-auth" and then stored it inside cookies.
On client side, using this token to signin like below:
axios({
url: "/api/users/login",
method: "POST",
data: {
email: data.email,
password: data.password
}
}).then(res => {
Cookies.set("x-auth", res.headers["x-auth"], { expires: 7 });
return firebase
.auth()
.signInWithCustomToken(res.headers["x-auth"])
.then(response => {
console.log("CA", response);
response
.getIdToken()
.then(idToken => {
Cookies.set("idToken", idToken, { expires: 7 });
})
.catch(e => {});
dispatch(
login({
token: Cookies.get("x-auth")
})
);
});
});
Now in order to call an api to fetch all users, I'm sending these tokens, custom token and idToken back to server:
const authenticate = (req, res, next) => {
const token = req.header("x-auth");
const idToken = req.header("idToken");
User.findByToken(token, idToken)
.then(user => {
if (!user) {
return Promise.reject({
message: "no user found with the associated token!"
});
}
req.user = user;
req.token = token;
next();
})
.catch(e => {
res.status(401).send(setErrorMessage(e.message));
});
};
And findByToken is as below:
UserSchema.statics.findByToken = function(token, idToken) {
var User = this;
return firebaseAdmin.default
.auth()
.verifyIdToken(idToken)
.then(function(decodedToken) {
var uid = decodedToken.uid;
return User.findOne({
_id: uid,
"tokens.access": "auth",
"tokens.token": token
});
})
.catch(function(e) {
return Promise.reject(e);
});
};
Why do I have to send both these tokens for authorization, is there anything wrong with the concept here.
https://firebase.google.com/docs/auth/admin/verify-id-tokens
Warning: The ID token verification methods included in the Firebase Admin SDKs are meant to verify ID tokens that come from the client SDKs, not the custom tokens that you create with the Admin SDKs. See Auth tokens for more information.
Please clarify if I can verify the custom token instead of idToken to retrieve userId and match it up with DB, instead of using different tokens for one purpose or I'm doing something wrong here and custom token should not be stored inside DB, and there is some other approach to it.
And now after sometime when I try to fetch all users, it says:
Firebase ID token has expired. Get a fresh token from your client app and try again (auth/id-token-expired). See https://firebase.google.com/docs/auth/admin/verify-id-tokens for details on how to retrieve an ID token.
When working with tokens, you need to differentiate each token and what it is used for, also each token has related properties.
Custom Tokens: These tokens will be generated in the server (as you are doing) and are used in the client side to authenticate the client. These tokens expire after one hour.
Session ID Token: (I'm calling it "Session ID Token" just to differentiate it) When the client autheticates with any of the authentication providers, the SDK will exchange the information for an ID token used for the session. The same applies for custom tokens, where the SDK exchanges the custom token for an ID Token. ID Tokens are also short live and will expire after one hour. When getting the ID Token, the SDK also receives a refresh Token which is used for refreshing the session ID Token. The ID token is used when doing authenticated requests to Firebase.
ID Token for verification: To get this token, you will need to call the function "getIDToken" (for Web). This function will return an ID Token that can be used only to verify requests coming from the client to your server. Similar to the other tokens, this one expires after one hour. When calling the getIDToken, the function will request a new one if the current is expired.
To verify the ID Token, you must use the mentioned token. If you try to use the session ID Token or the Custom token, you will get errors. The same applies if you try to use an expired ID Token.
All the calls and tasks to refresh the ID Tokens are handled by the SDKs behind the scenes.
It is not a good practice to store these tokens as they will expire after one hour, is better if you call the appropriate functions to get the latets tokens and pass the correct ID Token to be verified.
Lastly, you can find in these links the properties used for generating the custom token and the ID Token for verification.

Unexpected behavior when validating a session token using parse.com

I'm trying to build a simple application with parse.com as my user manager.
I would like to make a login call to parse.com from my client side, and call my node.js server with the user's session token (I'll add it as a cookie). In the server side, I'll validate the session (using https://parse.com/docs/rest#users-validating) and allow access only if the session is valid.
For example (in my server):
app.get('/api', function(req, res, next) {
var token = getTokenFromRequest(req);
if(tokenIsValid(token)) {
next();
} else { // Redirect... }
});
app.get('/api/doSomething', function(req, res) {
// Do something....
});
the tokenIsValid(token) function should be implemented using https://parse.com/docs/rest#users-validating.
However, it seems that the REST API user validation returns the user even if the user is logged out (expected to return 'invalid session').
Is this a bug in the REST API user validation? What am I doing wrong? Is there a better way for doing that?
Thanks!
Via REST there's no concept of sessions really. REST calls are meant to be stateless meaning that the (current) user at /me will be serialized from the token provided. If the token is associated to a user it will return the JSON representation of that user otherwise in returns an error.
One way or another that call is asynchronous so you can't really use it in and if statement.
You can do:
app.get('/api', function(req, res, next) {
var token = getTokenFromRequest(req);
serializeUserFromToken(token,function(err,parseResponse) {
if(err) return next(err)
if(parseResponse.code && parseResponse.code === 101){
// called to parse succedded but the token is not valid
return next(parseResponse);
}
// parseResponse is the current User.
next();
});
});
Where serializeUserFromToken makes a request to Parse with the token in the X-Parse-Session-Token header field.

Categories