I'm using the sailsjs framework on my server side and angularjs on my front end to build a SPA and using jsonwebtoken to do token authentication. My user api has the information: name: string, email: email, admin: Boolean, which are the information I use to generate the token and send to the front end save in localstorage.
My question is: how could I do to verify (check if the token is valid already is ready and everything is working) if the user is admin on my server-side?
Thank you in advance.
Below my current policy to check the token on the server-side
module.exports = function(req, res, next) {
var token;
if (req.headers && req.headers.authorization) {
var parts = req.headers.authorization.split(' ');
if (parts.length == 2) {
var scheme = parts[0],
credentials = parts[1];
if (/^Bearer$/i.test(scheme)) {
token = credentials;
}
} else {
return res.json(401, {
err: 'Format is Authorization: Bearer [token]'
});
}
} else if (req.param('token')) {
token = req.param('token');
// We delete the token from param to not mess with blueprints
delete req.query.token;
} else {
return res.json(401, {
err: 'No Authorization header was found'
});
}
sailsTokenAuth.verifyToken(token, function(err, token) {
if (err) {
console.log('ERR estou em tokenauth policies');
return res.json(401, {
err: 'The token is not valid'
});
}
req.token = token;
next();
});
};
Do 3 policies:
SetJwt: `req.
sailsTokenAuth.verifyToken(token, function(err, token) {
if (err) {
console.log('ERR estou em tokenauth policies');
return res.json(401, {
err: 'The token is not valid'
});
} else req.token = token
}
isAdmin:
if (req.auth === ADMIN_LEVEL) next()
else res.forbidden()
isUser:
if (req.auth === USER_LEVEL) next()
else res.forbidden()
Your policies:
someControllerMethod: [setJwt, isAdmin]
Of course you need to add an int or even a flag isadmin in your database for this to work. And the token needs to hold this information!
Related
Please refer to the following image.
I was able to successfully integrate the MFA with my Cognito pool and I am getting the OTP as well. Once the OTP is submitted I get the following error message as a 400 bad request. It seems MFA integration is working since once I entered the wrong code as the OTP then it shows the error message.
Once entered the correct OTP that I received into my mobile only I get this error message. Could someone please help me to sort out this issue?
I am expecting to get rid of this 400 Bad request error message which is returned by cognito endpoint call. Please find the below code for my cognito integration with the ReactJs project.
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: function(result) {
console.log("RESULT SUCCESS: ", result);
const accessToken = result.getAccessToken().getJwtToken();
console.log("ACCESS TOKEN: ", accessToken);
cognitoUser.getSession(function(err, session) {
if (err) {
console.log(err);
return;
}
// console.log('session validity: ' + session.isValid());
const totpMfaSettings = {
PreferredMfa: true,
Enabled: true
};
cognitoUser.setUserMfaPreference(null, totpMfaSettings, function(
err,
result
) {
if (err) {
console.log(err);
}
console.log("call result " + result);
});
});
},
onFailure: function(err) {
alert(err.message || JSON.stringify(err));
},
mfaSetup: function(challengeName, challengeParameters) {
console.log("MFA SETUP");
cognitoUser.associateSoftwareToken(this);
},
associateSecretCode: function(secretCode) {
const challengeAnswer = prompt("Please input the TOTP code.", "");
cognitoUser.verifySoftwareToken(
challengeAnswer,
"My TOTP device",
this
);
},
selectMFAType: function(challengeName, challengeParameters) {
var mfaType = prompt("Please select the MFA method.", ""); // valid values for mfaType is "SMS_MFA", "SOFTWARE_TOKEN_MFA"
cognitoUser.sendMFASelectionAnswer(mfaType, this);
},
totpRequired: function(secretCode) {
var challengeAnswer = prompt("Please input the TOTP code.", "");
cognitoUser.sendMFACode(challengeAnswer, this, "SOFTWARE_TOKEN_MFA");
},
mfaRequired: function(codeDeliveryDetails) {
var verificationCode = prompt("Please input verification code", "");
cognitoUser.sendMFACode(verificationCode, this);
},
newPasswordRequired: userAttributes => {
// XXXXXXXX
// This is somethign we need to fetch from an input
cognitoUser.completeNewPasswordChallenge("XXXXXXXX", {}, {
onSuccess: result => {
// login
console.log(result)
}
});
// };
}
});
I am trying to do authentication using identity server 4 for my react app.i followed this documentation.I am using implicit flow of identity server so onload application it will go to login page of identity server. after giving proper username and password it will validate and give a token.Everything is working as expected but i am not able to redirect my react app to Dashboard page.I am very new to react please help me.
// Copyright (c) Microsoft. All rights reserved.
import Config from 'app.config';
import AuthenticationContext from 'adal-angular/dist/adal.min.js'
import { Observable } from 'rxjs';
import { HttpClient } from 'utilities/httpClient';
import { toUserModel, authDisabledUser } from './models';
import Oidc, { User } from 'oidc-client';
const ENDPOINT = Config.serviceUrls.auth;
export class AuthService {
//static authContext; // Created on AuthService.initialize()
//static authEnabled = true;
//static aadInstance = '';
//static appId = '00000000-0000-0000-0000-000000000000';
//static tenantId = '00000000-0000-0000-0000-000000000000';
//static clientId = '00000000-0000-0000-0000-000000000000';
static initialize() {
if (typeof global.DeploymentConfig === 'undefined') {
alert('The dashboard configuration is missing.\n\nVerify the content of webui-config.js.');
throw new Error('The global configuration is missing. Verify the content of webui-config.js.');
}
if (typeof global.DeploymentConfig.authEnabled !== 'undefined') {
AuthService.authEnabled = global.DeploymentConfig.authEnabled;
if (!AuthService.authEnabled) {
console.warn('Auth is disabled! (see webui-config.js)');
}
}
//AuthService.tenantId = global.DeploymentConfig.aad.tenant;
//AuthService.clientId = global.DeploymentConfig.aad.appId;
//AuthService.appId = global.DeploymentConfig.aad.appId;
//AuthService.aadInstance = global.DeploymentConfig.aad.instance;
if (AuthService.aadInstance && AuthService.aadInstance.endsWith('{0}')) {
AuthService.aadInstance = AuthService.aadInstance.substr(0, AuthService.aadInstance.length - 3);
}
// TODO: support multiple types/providers
if (AuthService.isEnabled() && global.DeploymentConfig.authType !== 'aad') {
throw new Error(`Unknown auth type: ${global.DeploymentConfig.authType}`);
}
//AuthService.authContext = new AuthenticationContext({
// instance: AuthService.aadInstance,
//tenant: AuthService.tenantId,
//clientId: AuthService.clientId,
//redirectUri: "http://localhost:3000/dashboard",
//expireOffsetSeconds: 300, // default is 120
//postLogoutRedirectUri: window.location.protocol
//});
}
static isDisabled() {
return AuthService.authEnabled === false;
}
static isEnabled() {
return !AuthService.isDisabled();
}
static onLoad(successCallback) {
debugger;
AuthService.initialize();
if (AuthService.isDisabled()) {
console.debug('Skipping Auth onLoad because Auth is disabled');
if (successCallback) successCallback();
return;
};
var config = {
authority: "http://localhost:5000",
client_id: "mvc",
redirect_uri: "http://localhost:3000/dashboard",
response_type: "id_token token",
post_logout_redirect_uri : "http://localhost:5003/index.html",
};
var mgr = new Oidc.UserManager(config);
mgr.signinRedirect();
mgr.getUser().then(function(user){
if(user){
console.log("User logged in", user.profile);
}
else {
console.log("User not logged in");
}
});
mgr.events.addUserLoaded(function(userLoaded){
mgr.User=userLoaded;
})
mgr.events.addSilentRenewError(function (error){
console.log('the user has signrd out');
mgr._user=null;
})
//mgr.login();
//mgr.renewToken();
// Note: "window.location.hash" is the anchor part attached by
// the Identity Provider when redirecting the user after
// a successful authentication.
// if (AuthService.authContext.isCallback(window.location.hash)) {
// console.debug('Handling Auth Window callback');
// // Handle redirect after authentication
// AuthService.authContext.handleWindowCallback();
// const error = AuthService.authContext.getLoginError();
// if (error) {
// throw new Error(`Authentication Error: ${error}`);
// }
// } else {
// AuthService.getUserName(user => {
// if (user) {
// console.log(`Signed in as ${user.Name} with ${user.Email}`);
// if (successCallback) successCallback();
// } else {
// console.log('The user is not signed in');
// AuthService.authContext.login();
// }
// });
// }
}
static getUserName(callback) {
if (AuthService.isDisabled()) return;
if (AuthService.authContext.getCachedUser()) {
Observable.of({ Name:AuthService.authContext._user.userName, Email: AuthService.authContext._user.userName })
.map(data => data ? { Name: data.Name, Email: data.Email } : null)
.subscribe(callback);
} else {
console.log('The user is not signed in');
AuthService.authContext.login();
}
}
/** Returns a the current user */
static getCurrentUser() {
if (AuthService.isDisabled()) {
return Observable.of(authDisabledUser);
}
return HttpClient.get(`${ENDPOINT}users/current`)
.map(toUserModel);
}
static logout() {
if (AuthService.isDisabled()) return;
AuthService.authContext.logOut();
AuthService.authContext.clearCache();
}
/**
* Acquires token from the cache if it is not expired.
* Otherwise sends request to AAD to obtain a new token.
*/
static getAccessToken() {
debugger;
if (AuthService.isDisabled()) {
return Observable.of('client-auth-disabled');
}
return Observable.create(observer => {
return AuthService.authContext.acquireToken(
AuthService.appId,
(error, accessToken) => {
if (error) {
console.log(`Authentication Error: ${error}`);
observer.error(error);
}
else observer.next(accessToken);
observer.complete();
}
);
});
}
}
The problem i am facing is after authentication my app is going some kind of loop means the url of app is changing to identity server and local app url.you can see my app was using AuthenticationContext from adal previously.i want to change into oidc for identity server4.
I see that you mentioned redirect uri as dashboard? 'redirect_uri: "http://localhost:3000/dashboard'. So from the Identity server, the user will be redirected here right? Can you show us what you are doing on the dashboard page?
Typically, in Identity server implementation, redirect Uri needs to be a simple page whose responsibility needs to be nothing but accessing the Tokens from the URL and redirecting to the desired page (like redirecting to the dashboard from here)
I understand what I gave you is more of a theoretical answer, but seeing your implementation of redirect URL help you get a better answer.
I know how to read from the google finance api, it is pretty simple.
But when I try to write I get the following error:
Error: Request had insufficient authentication scopes
This is my code:
const fs = require('fs');
const readline = require('readline');
const {google} = require('googleapis');
// If modifying these scopes, delete token.json.
const TOKEN_PATH = 'token.json';
// Load client secrets from a local file.
fs.readFile('./GoogleFinanceApi/credentials.json', (err, content) => {
if (err) return console.log('Error loading client secret file:', err);
// Authorize a client with credentials, then call the Google Sheets API.
authorize(JSON.parse(content), appendData);
});
Here ^ in the append data is where I am calling the function, it works when i do the listMajors but not when I do the appendData...
function authorize(credentials, callback) {
const {client_secret, client_id, redirect_uris} = credentials.installed;
const oAuth2Client = new google.auth.OAuth2(
client_id, client_secret, redirect_uris[0]);
// Check if we have previously stored a token.
fs.readFile(TOKEN_PATH, (err, token) => {
if (err) return getNewToken(oAuth2Client, callback);
oAuth2Client.setCredentials(JSON.parse(token));
callback(oAuth2Client);
});
}
function listMajors(auth) {
const sheets = google.sheets({version: 'v4', auth});
sheets.spreadsheets.values.get({
spreadsheetId: '1ckHZsL2fnWVATmXljlewm-6qBo62B0qmu0w_2QdSpGA',
range: 'Sheet1!A2:E',
}, (err, res) => {
if (err) return console.log('The API returned an error: ' + err);
const rows = res.data.values;
if (rows.length) {
console.log('Name, Major:');
// Print columns A and E, which correspond to indices 0 and 4.
rows.map((row) => {
console.log(`${row[0]}, ${row[4]}`);
});
} else {
console.log('No data found.');
}
});
}
function appendData(auth) {
var sheets = google.sheets('v4');
sheets.spreadsheets.values.append({
auth: auth,
spreadsheetId: '1ckHZsL2fnWVATmXljlewm-6qBo62B0qmu0w_2QdSpGA',
range: 'Sheet1!A2:B', //Change Sheet1 if your worksheet's name is something else
valueInputOption: "USER_ENTERED",
resource: {
values: [ ["Void", "Canvas", "Website"], ["Paul", "Shan", "Human"] ]
}
}, (err, response) => {
if (err) {
console.log('The API returned an error: ' + err);
return;
} else {
console.log("Appended");
}
});
}
What am I doing wrong? I have read some posts and they say they didn't add the resource so I tried to fix that but still nothing works...
Probably the issue is in google.sheets in appendData. Perhaps you need to pass auth to google.sheets before you access sheets as how you are doing in listMajors but you are passing auth to the sheets instead of google.sheets. This might be an issue
Can you try below updated code
function appendData(auth) {
const sheets = google.sheets({version: 'v4', auth})
sheets.spreadsheets.values.append({
spreadsheetId: '1ckHZsL2fnWVATmXljlewm-6qBo62B0qmu0w_2QdSpGA',
range: 'Sheet1!A2:B', //Change Sheet1 if your worksheet's name is something else
valueInputOption: "USER_ENTERED",
resource: {
values: [ ["Void", "Canvas", "Website"], ["Paul", "Shan", "Human"] ]
}
}, (err, response) => {
if (err) {
console.log('The API returned an error: ' + err);
return;
} else {
console.log("Appended");
}
});
}
the function runs and console.log shows the user object on the backend. I don't understand why it's telling me there is an issue here, and really need some guidance.
vm.register = function() {
//check that passwords match
if(vm.password != vm.passwordRepeat) {
vm.registerError = "Passwords must match.";
return;
} else {
var username = vm.username;
// console.log("Valid form. Checking for existing user",username);
storeDataFactory.userExists(username).then(function(response){
//if user exists, return error
if(response.data.length > 0) {
vm.registerError = "A user with email " + username + " already exists. Please login.";
return;
} else {
//if no user exists
if(response.data.length == 0) {
// console.log("No user exists. Continue with registration.");
}
//assign info to user object
var user = {
username: vm.username,
password: vm.password,
name: vm.name,
phone: vm.phone
};
**storeDataFactory.createUser(user).then(function(response){**
vm.user = response.data;
console.log("Created user", vm.user);
if(response.data.length > 0) {
console.log("Created user", vm.user);
vm.registerMessage = "Successful registration, please login";
vm.registerError = null;
vm.user = response.data;
}
}).catch(function(error){
console.log(error);
vm.registerError = "There was an error creating your account.";
vm.registerMessage = null;
});
}
});
}
};
The backend code:
module.exports.register = function(req, res) {
console.log('registering user', req.body);
//create the user object with hashed pass
User
.create({
username: req.body.username,
name: req.body.name,
phone: req.body.phone,
password: bcrypt.hashSync(req.body.password, bcrypt.genSaltSync(10))
}, function(err, user) {
if (err) {
console.log("Error creating account");
res
.status(400)
.json(err);
} else {
console.log("Account created!", user);
res
.status(201)
.json(user);
}
});
};
Account created! and the user object are logged on the backend. It just won't display that damn Successful Registration! Please login. message.
storeDataFactory code:
/* global angular */ angular.module('rumbleApp').factory('storeDataFactory', storeDataFactory);
function storeDataFactory($http) {
return {
userExists: userExists,
createUser: createUser
};
function userExists(username) {
return $http.get('/api/users/userExists/' + username).then(complete).catch(failed);
}
function createUser(user) {
$http.post('/api/users/register', user).then(complete).catch(failed);
}
function complete(response) {
return response;
}
function failed(error) {
console.log(error.statusText);
return "There was an error with the API call.";
}
}
Are you sure you're returning from storeDataFactory.createUser()? Can you post the code for that method?
Sounds like the code is executing, but you're not returning anything from it (hence why it thinks it's undefined)
i'm trying to check if user already exite before register but not work for me
when i test in postman it's still created user any idea ?
create: function (req, res) {
if (req.body.password !== req.body.confirmPassword) {
return res.json(401, {err: 'Password doesn\'t match, What a shame!'});
}
User.find(req.body).exec(function(err,users){
if (err) {
return res.negotiate(err);
}
if (users.length) {
res.status(400);
return res.json('User already exists!');
}
}else{
User.create(req.body).exec(function (err, user) {
if (err) {
return res.json(err.status, {err: err});
}
// If user created successfuly we return user and token as response
if (user) {
// NOTE: payload is { id: user.id}
res.json(200, {user: user, token: jwToken.issue({id: user.id})});
}
});
}
});
try edit your code in this lines
User.find(req.body).exec(function(err,users){});
to :-
User.findOne({email:params.email}).exec(function(err,user){
if(user){
/**
*user exists !
*/
}else{
/**
*create new user
*/
}
}
because you use find with criteria which isn't exist so it's returns
null and create new user in every time
If you want to have users with unique username and/or email you can use unique type in model's attribute definition like this:
attributes: {
username: {
type: 'string',
unique: true
}
}
Then your controller method would look like this:
create: function (req, res) {
if (req.body.password !== req.body.confirmPassword) {
return res.json(401, {err: 'Password doesn\'t match, What a shame!'});
}
User.create(req.body, function (err, user) {
if (err) {
return res.negotiate(err); // validation error will be automatically passed there
}
res.json(200, {user: user, token: jwToken.issue({id: user.id})});
});
});