I can use https://xxx.au.auth0.com/api/v2/ to query and update the user. However not sur how to create roles and assign them to user.
Any idea please?
An easy way to do this is in Auth0 is with Rules - whereby you add the Roles information to the User Profile app_metadata attribute.
For example, here is a simple example
function addRolesToUser(user, context, callback) {
// ignore this rule if not correct client id of application using Rules
if (context.clientID !== 'eTQbNn3qxxxxxxxxxxxL6R7M7MDh') {
return callback(null, user, context);
}
user.app_metadata = user.app_metadata || {};
user.user_metadata = user.user_metadata || {};
// You can add a Role based on what you want
// In this case I check domain - give gmail ADMIN role
var addRolesToUser = function (user, cb) {
if (user.email.indexOf('#gmail.com') > -1) {
cb(null, ['ROLE_ADMIN', 'ROLE_USER']);
} else {
cb(null, ['ROLE_USER']);
}
};
addRolesToUser(user, function (err, roles) {
if (err) {
callback(err);
} else {
user.app_metadata.roles = roles;
auth0.users.updateAppMetadata(user.user_id, user.app_metadata)
.then(function () {
callback(null, user, context);
})
.catch(function (err) {
callback(err);
});
}
});
}
The Roles are now part of the User Profile and available in the app_metadata for inspection. If you additionally want the Roles information to appear in the returned JWT ID Token, just add the roles scope to your authentication request.
Related
I have a webservice which validates user/pwd and returns true/false (valid/invalid). I am trying to leverage Custom Authentication Workflow of AWS Cognito to integrate with the webservice.
I read through the docs and came across the define, create and verify lambda triggers and I tried those as follows:
Define trigger:
exports.handler = async (event) => {
if (!event.request.session || event.request.session.length === 0) {
event.response.challengeName = "CUSTOM_CHALLENGE";
event.response.failAuthentication = false;
event.response.issueTokens = false;
} else if (event.request.session.length === 1) {
// If we passed the CUSTOM_CHALLENGE then issue token
event.response.failAuthentication = false;
event.response.issueTokens = true;
} else {
// Something is wrong. Fail authentication
event.response.failAuthentication = true;
event.response.issueTokens = false;
}
return event;
};;
Create Trigger:
exports.handler = async (event) => {
if (event.request.challengeName == 'CUSTOM_CHALLENGE') {
event.response.publicChallengeParameters = {};
event.response.privateChallengeParameters = {};
}
return event;
}
Verify Trigger:
exports.handler = async (event, context) => {
//call webservice using "event.userName" and "event.request.challengeAnswer" (password)
var result = <bool-result-received-from-webservice>
event.response.answerCorrect = result;
return event;
};
The JS client looks like this:
Amplify.configure({
Auth: {
region: 'dd',
userPoolId: 'eeee',
userPoolWebClientId: 'ffff',
authenticationFlowType: 'CUSTOM_AUTH'
}
})
let user = await Auth.signIn(username)
.then(u => {
console.log(u); //(1) TOKENS ARE ALREADY CREATED HERE WITHOUT VERIFYING PASSWORD. NOT SURE.
if (u.challengeName === 'CUSTOM_CHALLENGE') {
console.log("responding to challenge..");
// to send the answer of the custom challenge
Auth.sendCustomChallengeAnswer(u, password)
.then(u2 => {
console.log("after responding to challenge...");
console.log(u2); //(2) NEW TOKENS ARE CREATED HERE. NOT SURE.
return u2;
})
.catch(err => {
console.log("ERROR with Challenge:");
console.log(err);
});
} else {
console.log("no challenge needed..");
return u;
}
})
.catch(err => {
console.log("ERROR with sign-in:..");
console.log(err);
});
I mentioned 1 and 2 in the comments above. Not sure if it's behaving correctly.
If the username is not in the "users" list of "user pool", it throws it as invalid login. Is it possible to validate username/password only through webservice having no "users" in the "user pool"?
I'm having trouble understanding how handle functions on Netlify. In particular, I want to access the user's id when they login.
I have enabled identity on my netlify site and I can login and log out.
<button data-netlify-identity-button id="login"></button>
I have created a function identity-login that I think should handle the user's details, but I cannot see how to utilise it on the web-page
// functions/identity-login.js
exports.handler = async function (event, context) {
const { identity, user } = context.clientContext;
console.log(identity, user)
return {
statusCode: 200,
body: 'hello'
}
};
The function endpoint is
https://silly-parrot.netlify.app/.netlify/functions/identity-login
I have this in the script on my page, but I don't know how to call it or if it's correct
async function apiCall() {
const url = `/.netlify/functions/identity-login`;
try {
const response = await fetch(url);
const data = await response;
console.log(data)
return data;
} catch (err) {
console.log(err);
}
}
What should I do?
I now realise that I was taking the wrong approach. It is not necessary to use the Netlify identity-login event. The netlifyIdentity object provides the necessary functionality for identifying when the user logs in or logs out and to discover whether or not the user is logged in when the page loads (init). The user identity is contained in the user.token.access_token
The following code is within my main js script (you will of course need to access the netlifyIdentity object)
<script type="text/javascript" src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
And then setup async functions to handle the authorisation events
<script>
var token = '';
var logged_in = false;
async function started() {
logged_in = false;
netlifyIdentity.on('init', async user => {
if(user) {
token = user.token.access_token;
logged_in = true;
}
console.log('init', logged_in, token);
})
netlifyIdentity.on('login', user => {
if(user) {
logged_in = true;
token = user.token.access_token;
}
console.log('log in', logged_in, token);
})
netlifyIdentity.on('logout', () => {
token = '';
logged_in = false;
console.log('log out', logged_in, token);
})
}
started()
</script>
I have the following code:
app.post("/login", (req, res) => {
const { username, password } = req.body;
// dummy local database with custome helper functions to look up a user:
db.users.findByUsername(username, (err, user) => {
if (!user) return res.status(403).json({ msg: "No user found!" });
if (user.password === password) {
// Adding properties to session
req.session.authenticated = true;
req.session.user = {
username,
password,
};
console.log(req.session);
// Session is printed in terminal with the above properties. Works fine up to here.
res.redirect("/shop");
} else {
res.status(403).json({ msg: "Bad Credentials" });
}
});
});
I used express-session to create a session and i'm storing it in memory. I created a middleware that would allow a user to access a /shop page only if they're authenticated and have the req.session.authenticated property set to true. For some reason, after they log in, and they're redirected to the /shop page, the properties created in the session are no longer there. Here's the rest of the code:
Authentication middleware:
function ensureAuthentication(req, res, next) {
if (req.session.authenticated) {
// Properties that were added upon logging in are not attached.
return next();
} else {
res.status(403).json({ msg: "You're not authorized to view this page" });
}
}
Shop page
app.get("/shop", ensureAuthentication, (req, res) => {
// Send the user object to the view page:
res.render("shop", { user: req.session.user });
});
Any opinions? Am I missing something here? Does the order of how I have the endpoints written matter?
I implemented passport-jwt to authenticate user on protected route and also i want to check maybe the user login before creating first admin, please help me on how to do it.
this is my passport-jwt code that i have implemented
exports.getToken = function (user) {
return jwt.sign(user, config.secretKey, { expiresIn: 3600 });
};
var opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = config.secretKey;
exports.jwtPassport = passport.use(
new JwtStrategy(opts, (jwt_payload, done) => {
console.log("JWT payload: ", jwt_payload);
User.findOne({ _id: jwt_payload._id, }, (err, user) => {
if (err) {
return done(err, false);
} else if (user) {
return done(null, user);
} else {
return done(null, false);
}
});
})
);
If I understand your question correctly, you have authenticated a user and (s)he's logged in. Now, before creating an admin, you want to check if the currently logged in user hasn't expired or something else. Right ?
To do that:
You need to store JWT on the client-side so that whenever you call your API, you can attach the JWT in your request's authentication header. I say Authentication header because your ExtractJWT Strategy is fromAuthHeaderAsBearerToken.
With this you can attach your token to subsequent API calls headers. You also need to implement a middleware on your server-side so that the controller can verify whether the JWT in the Authorization header is valid or invalid.
Here is a good resource to understand the pipeline. Note that in this resource, they fromUrlQueryParameter as the extract strategy, but the concept is the same.
I have a SPA which uses the solution provided here to authenticate with Azure AD and everything works as expected. Now I want to migrate this to use MSAL.js.
I use below for login:
import * as MSAL from 'msal'
...
const config = {
auth: {
tenantId: '<mytenant>.com',
clientId: '<myclientid>',
redirectUri: <redirecturi>,
},
cache: {
cacheLocation: 'localStorage',
}
};
const tokenRequest = {
scopes: ["User.Read"]
};
export default {
userAgentApplication: null,
/**
* #return {Promise}
*/
initialize() {
let redirectUri = config.auth.redirectUri;
// create UserAgentApplication instance
this.userAgentApplication = new MSAL.UserAgentApplication(
config.auth.clientId,
'',
() => {
// callback for login redirect
},
{
redirectUri
}
);
// return promise
return new Promise((resolve, reject) => {
if (this.userAgentApplication.isCallback(window.location.hash) || window.self !== window.top) {
// redirect to the location specified in the url params.
}
else {
// try pull the user out of local storage
let user = this.userAgentApplication.getUser();
if (user) {
resolve();
}
else {
// no user at all - go sign in.
this.signIn();
}
}
});
},
signIn() {
this.userAgentApplication.loginRedirect(tokenRequest.scopes);
},
And then I use below to get the token:
getCachedToken() {
var token = this.userAgentApplication.acquireTokenSilent(tokenRequest.scopes);
return token;
}
isAuthenticated() {
// getCachedToken will only return a valid, non-expired token.
var user = this.userAgentApplication.getUser();
if (user) {
// get token
this.getCachedToken()
.then(token => {
axios.defaults.headers.common["Authorization"] = "Bearer " + token;
// get current user email
axios
.get('<azureapi-endpoint>' + '/GetCurrentUserEmail')
.then(response => { })
.catch(err => { })
.finally(() => {
});
})
.catch(err => { })
.finally(() => { });
return true;
}
else {
return false;
}
},
}
but after login I get below error:
Access to XMLHttpRequest at 'https://login.windows.net/common/oauth2/authorize?response_type=code+id_token&redirect_uri=<encoded-stuff>' (redirected from '<my-azure-api-endpoint>') from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Also the token that I get seems to be invalid as I get 401 errors trying to call api using the token. Upon checking the token against https://jwt.io/ I get an invalid signature.
I really appreciate anyone's input as I've already spent good few days and haven't got anywhere yet.
I'm not sure if this is your issue. however, for msal.js, in the config, there is no tenantId parameter, it's supposed to be authority. Here is a sample for graph api using msal.js
https://github.com/Azure-Samples/active-directory-javascript-graphapi-v2
specifically: the config is here: https://github.com/Azure-Samples/active-directory-javascript-graphapi-v2/blob/quickstart/JavaScriptSPA/authConfig.js
as per here, https://learn.microsoft.com/en-us/azure/active-directory/develop/msal-js-initializing-client-applications it is supposed to be hitting login.microsoftonline.com not login.windows.net