How to get the value from new Msal.UserAgentApplication(applicationConfig.clientID)? - azure-ad-b2c

This is my first experience with MSAL.js.
In Azure AD B2C I'm trying to get the value from the userid that is entered into popup login screen generate by a signin policy which is called from an html file.
var clientApplication = new Msal.UserAgentApplication(applicationConfig.clientID, applicationConfig.authority, function (errorDesc, token, error, tokenType) {
// Called after loginRedirect or acquireTokenPopup
});
function login() {
clientApplication = new Msal.UserAgentApplication(applicationConfig.clientID, applicationConfig.authority, function (errorDesc, token, error, tokenType) {
// Called after loginRedirect or acquireTokenPopup
});
clientApplication.loginPopup(applicationConfig.b2cScopes, "login_hint=user#domain.com").then(function (idToken) {
clientApplication.acquireTokenSilent(applicationConfig.b2cScopes).then(function (accessToken) {
updateUI();
}, function (error) {
clientApplication.acquireTokenPopup(applicationConfig.b2cScopes).then(function (accessToken) {
updateUI();
}, function (error) {
logMessage("Error acquiring the popup:\n" + error);
});
})
}, function (error) {
reset();
logMessage("Error during login:\n" + error);
});
The user is entering userid#domain.com I need to retrieve this value so that I can parse out the domain name.
How to extract the userid?

You could use getUser‎() to extract the userid. For the details, please refer to here.

Related

Is my Paypal checkout flow Angular-Node secure?

I'm developing a paypal checkout using the 'basic Smart Payment Buttons integration' and integrating it with server Node installing the 'checkout-server-sdk'.
I followed the documentations:
https://developer.paypal.com/docs/checkout/reference/server-integration/set-up-transaction/
https://github.com/paypal/Checkout-NodeJS-SDK
where they suggest to:
'createOrder' starting from the client and calling the server
generating on the server an orderID and return it to the client
'onApprove' send to the server the orderID and approve it on the server
return back to the client the response
I don't think it is a good flow.
Someone could:
start the payment
so the app create the order on the server taking the shoppingcart from db and elaborate a totalPrice of 100euros.
generete the orderID and send it back to the client
instead of approve this order, a 'bad user' could, in some way, send to the server another orderID that could correspond to a lower price (2euros)
so he could approve the payment of 2 euros
So I don't understand why we need to make the checkout jumping more times from client to server.
Or maybe am i doing something wrong on my checkoutflow ?
unfortunately I feel the Paypal documentation so unclear.
checkout.component.html
<!-- * here there is a form where i get shipment info, invoice info and so on ->
<!-- * PAYPAL SMART BUTTONS -->
<div>
<div #paypal></div>
</div>
checkout.component.ts
onFormSubmit() {
this.isFormSubmitted = true;
// set paypal settings and show the paypal buttons
this.paypalSetting(this.shippmentInfo, this.invoiceRequired, this.invoice, this.addressInvoice);
}
async paypalSetting(shipment, invoiceRequired, invoice, addressInvoice) {
await paypal
.Buttons({
style: {
size: 'responsive',
label: 'pay',
},
experience: {
input_fields: {
no_shipping: 1,
},
},
createOrder: async (data, actions) => {
console.log('CREATE ORDER -->');
var paypalOrderId;
//generate new order
await this.apiService.newOrder().toPromise().then(
(res) => {
console.log('ON CREATE: SUCCESSFULLY CREATED')
paypalOrderId = res.order.paypalOrderId;
// ????? someone here could change 'paypalOrderId' with another value !!!!
//I also would like to return the 'paypalOrderId' only here !!
},
(err) => {
console.log('ON CREATE: ERROR: ' + err);
// how should i manage this error ? i should skip the flow to onError but HOW ?
}
);
return paypalOrderId;
},
onApprove: async (data, actions) => {
console.log('APPROVE ORDER -->');
var paypalOrderId = data.orderID;
console.log('ON APPROVE: save the order on server/DB')
await this.apiService.saveOrder(shipment, invoiceRequired, invoice, addressInvoice, paypalOrderId).toPromise().then(
(res) => {
console.log('ON APPROVE: ORDER APPROVED')
this.isPaid = true;
//if isPaid i can show a 'success page'
},
(err) => {
console.log('ON APPROVE: ERROR: ' + err);
this.isPaid = false;
}
);
},
onError: (err) => {
console.log('ON ERROR: ' + err);
},
})
.render(this.paypalElement.nativeElement);
}
Node api.js
//* paypal
const paypal = require('#paypal/checkout-server-sdk');
const payPalClient = require('../paypalManager');
router.post('/newOrder', tokenManager.verifyAccessToken, async function (req, res, next) {
const idUser = req.userId;
// I get the shoppingcart of the user 'idUser'
// i calculate the total price
var totalPrice;
//* Call PayPal to set up a transaction
let order;
const request = new paypal.orders.OrdersCreateRequest();
request.prefer("return=representation");
request.requestBody({
intent: 'CAPTURE',
purchase_units: [{
description: 'payment ecc..', /
amount: {
currency_code: 'EUR',
value: totalPrice
}
}],
application_context: {
brand_name: "brand",
shipping_preference: 'NO_SHIPPING',
},
});
let response = await payPalClient.client().execute(request);
order = response;
const paypalOrderId = order.result.id;
// return a successful response to the client with the order ID
return res.json({
status: 200,
order: {
paypalOrderId: paypalOrderId,
},
message: "Paypal order sucessfully created",
});
});
router.post('/saveOrder', tokenManager.verifyAccessToken, async function (req, res, next) {
const idUser = req.userId;
var paypalOrderId = req.body.paypalOrderId;
try {
connection.beginTransaction(async () => {
try {
// here i insert all the checkout infos in DB
// confirm the queries executions
connection.commit(async function (err) {
if (err) {
//return connection.rollback(function () {
connection.rollback(function () {
return next(createError.Unauthorized("Sql query error: " + err)); //! or error.message
});
}
//* here i send the Emails to confirm the checkout
//* capture/approve the order
console.log('CAPTURING THE ORDER')
var request = new paypal.orders.OrdersCaptureRequest(paypalOrderId);
request.requestBody({});
// Call API with your client and get a response for your call
let response = await payPalClient.client().execute(request);
//*response
return res.json({
status: 200,
message: "Paypal sucessfully approved",
});
});// end commit
} catch (error) {
connection.rollback(function () {
return next(createError.Unauthorized("Sql query error " + error)); //! or error.message
});
}
});// end transaction
} catch (error) {
return next(error);
}
});
Node paypalManager.js
'use strict';
/**
* PayPal Node JS SDK dependency
*/
const checkoutNodeJssdk = require('#paypal/checkout-server-sdk');
/**
* Returns PayPal HTTP client instance with environment that has access
* credentials context. Use this instance to invoke PayPal APIs, provided the
* credentials have access.
*/
function client() {
return new checkoutNodeJssdk.core.PayPalHttpClient(environment());
}
/**
* Set up and return PayPal JavaScript SDK environment with PayPal access credentials.
* This sample uses SandboxEnvironment. In production, use LiveEnvironment.
*/
function environment() {
let clientId = process.env.PAYPAL_CLIENT_ID;
let clientSecret = process.env.PAYPAL_CLIENT_SECRET;
return new checkoutNodeJssdk.core.SandboxEnvironment(
clientId, clientSecret
);
}
module.exports = {
client: client,
prettyPrint: prettyPrint
};
The reason you are "jumping" between the client and the server, is the approval by the payer has to happen on the client. The payer cannot give their approval on your server, they are not sitting on your server. They are using a client browser.
Regarding:
a 'bad user' could, in some way, send to the server another orderID that could correspond to a lower price (2euros)
If this happens, your server should reject the undesired transaction, and not proceed with it. That's the point of having a server. Nothing happens unless your server OKs it.

How to pass extra data and check if token is valid with JWT

I just started a project where I have to use Node + few things related to it and I feel a little confused!
I use JWT for authentication, particularly I created my project like this:
api
|---teams
|----teams.controller.js
|----teams.router.js
|----teams.service.js
|---users (same as team)
auth
|---token_validation.js
other things
|---other things
I use token_validation.js for JWT to validate user while login and seems it work (verified with Postman)
const jwt = require("jsonwebtoken");
module.exports = {
checkToken: (req, res, next) => {
let token = req.get("authorization");
if (token) {
// Remove Bearer from string
token = token.slice(7);
jwt.verify(token, process.env.JWT_KEY, (err, decoded) => {
if (err) {
console.log("err: " + err);
return res.json({
success: 0,
message: "Invalid Token..."
});
} else {
req.decoded = decoded;
next();
}
});
} else {
// other code
}
}
};
I need to insert a new team in DB (MariaDB) and user can create a new team after login. My problem is that while using Session in Java for e.g. I can easly set extras like username of the logged in user and when I need to know what's the username of the logged in user is, I can take it from session
String username = (String) session.getAttribute("username");
I can't understand how to do the same with Node/JWT. What I need to do is, after login I need to save the user_id and when user crate a new team I need to send to DB the user_id with other data (if token still valid).
const {
create
} = require("./teams.service");
module.exports = {
createTeam: (req, res) => {
const body = req.body;
// here I need to check if token still valid
// if yes -> take user id and send it to DB with
// other data
create(body, (err, results) => {
if (err) { // if fails
// handle
}
return res.status(200).json({ // success
success: 1,
data: results
});
});
},
}
I thought I could add it in user.controller.js when user login:
if (result) {
results.password = undefined;
const jsontoken = sign({ result: results }, process.env.JWT_KEY, {
expiresIn: "1h",
user_id: get somehow //error
});
// other code
}
but it gives me an error, tells me like I can't add user_id to sign. Can anyone please tell me the right way to store and get this kind of data and use them when needed while user still have a valid token to stay logged in?
You are adding your data to the options, not the payload.
if (result) {
results.password = undefined;
results.user_id = XXXXXXXX //get somehow
const jsontoken = sign({ result: results }, process.env.JWT_KEY, {
expiresIn: "1h"
});
...
}
Best option is to set it in localStorage. When you make a req to backend send it with headers, then in backend check if token is valid and send response with data that you want.

Check If Firebase User Exist Without Throwing Error

I have a website that offers a simple messaging service. Individuals can pay for the service, or a business can pay for a monthly subscription and then add their clients/users for free. When the business adds a client/user email, that triggers the function below. I'm using firebase functions and createUser to create the user on my server(less). However, sometimes a business tries to register a user and that user already exist. In this case, I want to send the user a reminder email.
The code I have works fine, but it feels funky having a chain within my catch/error. Is there another way to detect if an email is already registered with a Firebase account that won't throw an error?
exports.newUserRegisteredByBusiness = functions.database.ref('users/{uid}/users/invited/{shortEmail}').onWrite( (data, context) => {
//don't run function if data is null
if (!data.after.val()){
console.log('SKIP: newUserRegisteredByBusiness null so skipping')
return null
} else {
let businessUID = context.params.uid
let email = data.after.val()
let shortEmail = context.params.shortEmail
let password // = something I randomly generate
return admin.auth().createUser({ email: email, password: password}).then( (user)=> {
//write new user data
let updates = {}
let userData // = stuff I need for service to run
updates['users/' + user.uid ] = userData;
return admin.database().ref().update(updates)
}).then( () =>{
//email new user about their new account
return emailFunctions.newUserRegisteredByBusiness(email, password)
}).catch( (error) =>{
//if user already exist we will get error here.
if (error.code === 'auth/email-already-exists'){
//email and remind user about account
return emailFunctions.remindUsersAccountWasCreated(email).then( ()=> {
//Once email sends, delete the rtbd invite value that triggered this whole function
//THIS IS WHERE MY CODE FEELS FUNKY! Is it ok to have this chain?
return admin.database().ref('users/' + businessUID + '/users/invited/' + shortEmail).set(null)
})
} else {
//delete the rtbd value that triggered this whole function
return admin.database().ref('users/' + businessUID + '/users/invited/' + shortEmail).set(null)
}
});
}
})
To find if a user account was already created for a given email address, you call admin.auth().getUserByEmail.
admin.auth().getUserByEmail(email).then(user => {
// User already exists
}).catch(err => {
if (err.code === 'auth/user-not-found') {
// User doesn't exist yet, create it...
}
})
While you're still using a catch() it feels like a much less failed operation.
To avoid further implementation in the catch block you can wrap this Firebase function into this code:
async function checkUserInFirebase(email) {
return new Promise((resolve) => {
admin.auth().getUserByEmail(email)
.then((user) => {
resolve({ isError: false, doesExist: true, user });
})
.catch((err) => {
resolve({ isError: true, err });
});
});
}
...
const rFirebase = await checkUserInFirebase('abc#gmail.com');

How to Update offline user record on parse.com ?

I am developing a referral system, in which I will increase invite counter of inviter.
I did a lot search but didn't find working example.
Bellow is the code
app.get('/increase-counter', function( request, response ) {
//Sdk Link: http://blog.parse.com/2012/10/11/the-javascript-sdk-in-node-js/
var Parse = require('parse-cloud').Parse;
Parse.initialize( config.parse.appId, config.parse.jsKey );
Parse.Cloud.define("modifyUser", function(request, response) {
console.log('hello4');
if (!request.user) {
response.error("Must be signed in to call this Cloud Function.")
console.log('hello5');
return;
}
// The user making this request is available in request.user
// Make sure to first check if this user is authorized to perform this change.
// One way of doing so is to query an Admin role and check if the user belongs to that Role.
// Replace !authorized with whatever check you decide to implement.
if (!authorized) {
console.log('hello6');
response.error("Not an Admin.")
return;
}
// The rest of the function operates on the assumption that request.user is *authorized*
Parse.Cloud.useMasterKey();
// Query for the user to be modified by username
// The username is passed to the Cloud Function in a
// key named "username". You can search by email or
// user id instead depending on your use case.
var query = new Parse.Query(Parse.User);
//query.equalTo("username", request.params.username);
query.equalTo("objectId", req.query.objectId);
console.log('hello7');
// Get the first user which matches the above constraints.
query.first({
success: function(anotherUser) {
console.log('hello8',anotherUser);
// Successfully retrieved the user.
// Modify any parameters as you see fit.
// You can use request.params to pass specific
// keys and values you might want to change about
// this user.
anotherUser.set("inviteCounter", 2);
// Save the user.
anotherUser.save(null, {
success: function(anotherUser) {
// The user was saved successfully.
response.success("Successfully updated user.",anotherUser);
},
error: function(gameScore, error) {
// The save failed.
// error is a Parse.Error with an error code and description.
response.error("Could not save changes to user.",gameScore,error);
}
});
},
error: function(error) {
response.error("Could not find user.",error);
}
});
});
console.log('hello1');
Parse.Cloud.run('modifyUser', { objectId: request.query.objectId }, {
success: function(status) {
console.log('hello2');
// the user was updated successfully
},
error: function(error) {
console.log('hello3', error);
// error
}
});
});
When I run url, its showing result in terminal:
hello1
hello3 { code: 141, message: 'function not found' }
Please let me know how could I update the inviteCounter ?

authentication using node.js and mongodb

Guys I am trying to get myself authenticated and for this I am using node.js and mongo DB.But the thing is that after registarion the user is not able to authenticate himself.Here is my snippet
app.post('/login',function(req,res){
ContactProvider.findAll(function(error, posts) {
var aut = req.body;
if (aut.user == posts.user && aut.pass == posts.pass) {
req.session.name = {name:aut.user};
res.redirect('/home');
} else {
res.send('Bad user/pass');
}
});
});
Below is my snippet for registering the user
app.post('/register',function(req, res) {
var post=req.body;
if(post.pass!=post.cpass) {
res.send("Error:Password doesnt match");
} else {
ContactProvider.save({
user: req.param('user'),
pass: req.param('pass'),
cpass: req.param('cpass'),
email: req.param('email')
}, function(error, docs) {
res.redirect('/');
});
}
});
The ContactProvider is the one below where post provider is a different file where all the mongoose things happen
var ContactProvider = require('./PostProvider').ContactProvider;
var ContactProvider= new ContactProvider();
This is the finone query in the postprovider file
ContactProvider.prototype.findone = function(name,pass, callback) {
Post.findOne({name:name},{pass:pass}, function (err, post) {
callback(null, post);
});
};
Something's seriously wrong with your code ( why you use name posts for an array of ContactProvider? ). You have to search for ContactProvider based on username and password. Something like this:
app.post('/login',function(req,res){
var aut = req.body;
ContactProvider.findOne(
{
user: aut.user,
pass: aut.pass
},
function(err, usr) {
if (error || !usr) {
res.send('Bad user/pass');
} else {
// we have a user, authenticate!
req.session.name = {name:aut.user};
res.redirect('/home');
}
}
);
});
SIDE NOTE: This is a very simple way of authenticating users, but it is not secure at all. You should read more about authentication and security in the internet. Very useful knowledge indeed.
EDIT: There's also an issue with your registration. Your data is stored in post variable, so use it on ContactProvider as well:
// some other code
ContactProvider.save({
user: post.user,
pass: post.pass,
cpass: post.cpass, // no need to store the same thing twice
email: post.email

Resources