Auth0 NodeJS Authentification Refused using npm request - angularjs

I'm facing a problem, I tried to connect to Auth0 API to enable a strong identification on my WebApp.
For context :
Front-End : I'm using an angularJS front, and there I implemented the Lock Library to manage the Auth0 popup by following this webapp-specific tutorial.
Back-End : NodeJS & Express server, in order to verify the user's authentification, I use the npm lib "request" to call the Auth0 API.
If i understand well, a click on the auth0 widget sends a request to the specified endpoint URL, and it's received by the back-end:
app.get('/auth0CallbackURL', function (req, res) {
console.log(req.query.code);
var auth0code = req.query.code;
var client_secret = PROCESS.ENV.SERCRETID;
var domain = PROCESS.ENV.DOMAIN;
var client_id = PROCESS.ENV.CLIENTID;
var redirectUrl = PROCESS.ENV.REDIRECTURL;
var request = require('request'); // request-promise
var requestParams = {
url: 'https://mycompanydomain.auth0.com/oauth/token?client_id='+client_id+'&redirect_uri='+redirectUrl+'&client_secret='+client_secret+'&code='+auth0code+'&grant_type=authorization_code',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
And then I call request() to get back the access_token and verify the authentification.
request(requestParams, function(err, data) {
if (err) {
console.log('Err:', err);
} else {
console.log('response body: ', data.body)
}
But the only result I get is :
{
"error": "access_denied"
"error_description": "Unauthorized"
}
At the begining i thougt it was my Auth0 configuration that's didn't allow my authentification, but it seems that there are OK.
Thanks in advance for your replies.

As per the page you linked, you need to pass the following information:
client_id=YOUR_CLIENT_ID
&redirect_uri=https://YOUR_APP/callback
&client_secret=YOUR_CLIENT_SECRET
&code=AUTHORIZATION_CODE
&grant_type=authorization_code
in the request body and with a content type of application/x-www-form-urlencoded.
You're setting the content type correctly, but then are passing the data in the URL query component and instead you need to pass it the POST request body.
Using request package you should do the following:
var requestParams = {
url: 'https://mycompanydomain.auth0.com/oauth/token',
method: 'POST',
body: 'client_id=' + client_id +
'&redirect_uri=' + redirectUrl +
'&client_secret=' + client_secret +
'&code=' + auth0code +
'&grant_type=authorization_code',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}

Related

Redirect from React ASP.NET application to SSO login page blocked by CORS Policy

My application is set up as of follows:
Frontend is React (SPA),
Backend is ASP.NET Core 6, and
User will be authenticated via SSO using SAML2 protocol (the SAML code is implemented on the ASP.NET side, not React)
When the React page is loaded, it will send a POST request via fetch API to the ASP.NET server which then will trigger to load the SSO page (I'm actually confused by this as I'm unsure how this would work with React since React handles all the routing piece here). However, I keep getting an error that is saying:
"Access to fetch at 'https://sso.example.com/saml/idp/profile/redirectorpost/sso?SAMLRequest=xxxx&RelayState=ReturnUrl%3D%252Fexample%252Fexampleapp%252FGetLoggedInUser' (redirected from 'https://forms.test.com/test/testapp/GetLoggedInUser') from origin 'https://forms.test.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request."
I attempted to fix this by changing the attributes in the fetch headers by all resulted in the same CORS error.
Here's my fetch api code on the frontend:
fetch("testapp/GetLoggedInUser", {
method: "POST",
headers: {
'Accept': 'application/json',
'Access-Control-Allow-Origin': '*',
},
body: data
}).then((response) => {
const contentType = response.headers.get("content-type");
if (contentType && contentType.indexOf("application/json") !== -1) {
return response.json().then((data) => {
return data;
}).catch((err) => {
console.log(err);
})
}
else {
return response.text().then((data) => {
return data;
}).catch((err) => {
console.log(err);
})
}
});
My backend (ASP.NET Core 6)
//[Authorize] is an attribute from Microsoft.AspNetCore.Authorization.AuthorizeAttribute
[Authorize]
[HttpPost("GetLoggedInUser")]
public string GetLoggedInUserData()
{
this.CheckSession();
Person Person = new ActiveUser(this.ID, GlobalVariables.ProcessCode);
dynamic P = Person.GetSimple();
User User = new User(this.WhitworthID);
P.LastAccess = DateTime.Now;
User.SetLastAccess();
return JsonConvert.SerializeObject(P);
}
Can anyone advise me on how to get past the CORS error when redirecting from React to the SSO page?
Modify your code to check if the response is redirected,if so redirect the browser to the new url.
fetch(url, { method: 'POST', redirect: 'manual'})
.then(response => {
// HTTP 301 response
// HOW CAN I FOLLOW THE HTTP REDIRECT RESPONSE?
if (response.redirected) {
window.location.href = response.url;
}
})
.catch(function(err) {
console.info(err + " url: " + url);
});

CORS error while sending request from Browser to play server even after sending CORS header

I have a REST API developed using Play Framework/Java and front end developed in Angular JS.
I am trying to call a POST method fron the Angular Client to the server using the following code:
$scope.login = function () {
console.log('login called');
var loginURL = 'http://localhost:9000/login';
var loginInfo = {
'email': $scope.email,
'password': $scope.password
};
$http({
url: loginURL,
method: 'POST',
data: loginInfo,
headers: { 'Content-Type': 'application/json' }
}).then(function (response) {
console.log('SUCCESS: ' + JSON.stringify(response));
$scope.greeting = response.status;
}, function (response) {
console.log('ERROR: ' + JSON.stringify(response));
});
}
This is the code at my server:
public Result doLogin() {
ObjectNode result = Json.newObject();
result.put("status", "success");
return ok(result).withHeader("Access-Control-Allow-Origin", "*");
}
And this is the application conf file:
#allow all hosts.
play.filter.hosts {
allowed = ["."]
}
#allow CORS requests.
play.filters.cors {
allowedOrigins = ["*"]
}
Yet even after enabling CORS, I am getting error in console in both Firefox and Google Chrome:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:9000/login. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
ERROR: {"data":null,"status":-1,"config":{"method":"POST","transformRequest":[null],"transformResponse":[null],"jsonpCallbackParam":"callback","url":"http://localhost:9000/login","data":{"email":"xxx","password":"xxx"},"headers":{"Content-Type":"application/json","Accept":"application/json, text/plain, /"}},"statusText":""}
I do know that the server is sending the correct response and the correct header because when I do the POST from Postman, I can see the response and also the headers containing {"Access-Control-Allow-Origin", "*"} in Postman.
So then, what could be the problem? Is there something I am missing from the Client side?
The difference between POSTMAN request and browser request is browser sends an OPTIONS request before the actual POST / GET request.
To be able to accept OPTION request with your play framework allowedHttpMethods = ["GET", "POST" ,"OPTIONS"]
for follow this link
Play Framework 2.3 - CORS Headers
This causes a problem accessing CORS request from a framework (like angularjs). It becomes difficult or the framework to find what was the options request for and take action properly.
For fixing your problem you will need to analyze how the options request going and how it's being interpreted and how to overcome. But in general, I suggest using "fetch" built-in request for this, which supports the promises so can be chained easily with angularjs code
so your code will look something like this
$scope.login = function () {
console.log('login called');
var loginURL = 'http://localhost:9000/login';
var loginInfo = {
'email': $scope.email,
'password': $scope.password
};
fetch(loginURL, {
method: 'post',
headers: {
"Content-type": "application/json"
},
body: loginInfo
}).then(function (response) {
console.log('SUCCESS: ' + JSON.stringify(response));
$scope.greeting = response.status;
}, function (response) {
console.log('ERROR: ' + JSON.stringify(response));
});
}

Angularjs Access-Control-Allow-Origin

I have Angularjs app connects to a server using API, and i'm using token authentication, when i use Postman to get the token, it works perfect, but when i'm use Angulajs with the same header and parameters i got error:400.
When i checked both requests using Fiddler, i found that the request from Angularjs is missing Access-Control-Allow-Origin: * header.
How to fix this?
Here is the service used to get the token:
AuthenticationApi.Login = function (loginData) {
//POST's Object
var data = "grant_type=password&username=" + loginData.userName + "&password=" + loginData.password;
var deferred = $q.defer();
//the data will be sent the data as string not JSON object.
$http.post('http://localhost:53194/Token', data, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } })
.then(function (response) {
console.log(response);
localStorageService.set('authorizationData',
{
token: response.access_token,
userName: loginData.userName
});
Authentication.isAuth = true;
Authentication.userName = loginData.userName;
console.log(Authentication);
deferred.resolve(response);
},
function (err, status) {
logout();
deferred.reject(err);
});
return deferred.promise;
};
for the API server, i'v done CORS:
public void Configuration(IAppBuilder app)
{
ConfigureOAuth(app);
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
}
i found the problem and i fixed it.
in the API server, i have this code:
var cors = new EnableCorsAttribute("*", "*", "*");
cors.PreflightMaxAge = 60;
config.EnableCors(cors);
The problem is in the PreflightMaxAge, i just commented it...It worked!!!
if the problem not solved, try to use IE or FireFox, don't use Chrome because it is not CORS enabled

Nodejs sending external API POST request

i am trying to send a POST request from my angularjs controller to the nodejs server which should then send a full POST request to the external API and this way avoid CORS request as well as make it more secure as i'm sending relatively private data in this POST request.
My angularjs controller function for making the post request to the nodejs server looks like this and it works fine:
var noteData = {
"id":accountNumber,
"notes":[
{
"lId":707414,
"oId":1369944,
"nId":4154191,
"price":23.84
}
]
}
var req = {
method: 'POST',
url: '/note',
data: noteData
}
$http(req).then(function(data){
console.log(data);
});
Now the problem lies in my nodejs server where i just can't seem to figure out how to properly send a POST request with custom headers and pass a JSON data variable..
i've trierd using the nodejs https function since the url i need to access is an https one and not http ,i've also tried the request function with no luck.
I know that the url and data i'm sending is correct since when i plug them into Postman it returns what i expect it to return.
Here are my different attempts on nodejs server:
The data from angularjs request is parsed and retrieved correctly using body-parser
Attempt Using Request:
app.post('/buyNote', function (req, res) {
var options = {
url: 'https://api.lendingclub.com/api/investor/v1/accounts/' + accountNumber + '/trades/buy/',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': apiKey
},
data = JSON.stringify(req.body);
};
request(options, function (error, response, body) {
if (!error) {
// Print out the response body
// console.log(body)
console.log(response.statusCode);
res.sendStatus(200);
} else {
console.log(error);
}
})
This returns status code 500 for some reason, it's sending the data wrongly and hence why the server error...
Using https
var options = {
url: 'https://api.lendingclub.com/api/investor/v1/accounts/' + accountNumber + '/trades/buy/',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': apiKey
}
};
var data = JSON.stringify(req.body);
var req = https.request(options, (res) => {
console.log(`STATUS: ${res.statusCode}`);
console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
res.setEncoding('utf8');
res.on('data', (chunk) => {
console.log(`BODY: ${chunk}`);
});
res.on('end', () => {
console.log('No more data in response.');
});
});
req.on('error', (e) => {
console.log(`problem with request: ${e.message}`);
});
req.write(data);
req.end();
Https attempt return a 301 status for some reasons...
Using the same data, headers and the url in Postman returns a successful response 200 with the data i need...
I don't understand how i can make a simple http request...
Please note: this is my first project working with nodejs and angular, i would know how to implement something like this in php or java easily, but this is boggling me..
So after a lot of messing around and trying different things i have finally found the solution that performs well and does exactly what i need without over complicating things:
Using the module called request-promise is what did the trick. Here's the code that i used for it:
const request = require('request-promise');
const options = {
method: 'POST',
uri: 'https://requestedAPIsource.com/api',
body: req.body,
json: true,
headers: {
'Content-Type': 'application/json',
'Authorization': 'bwejjr33333333333'
}
}
request(options).then(function (response){
res.status(200).json(response);
})
.catch(function (err) {
console.log(err);
})

Drupal REST return 301 after logging in from ionic application

I have web application based on drupal 7, and I want to create ionic app connected with that web app using REST.
Login action work good, but after login I always get status 301 Moved Permamently, no matter what I call from REST.
But when I do the same using ARC or POSTMASTER all works good. I can call login successfully, get token successfully, and logout without any problem.
I guess the reason is not set header properly. When I use ARC or POSTMASTER my request contains Cookie with session_name and sessid received from drupal during login.
Also I cant set X-CSRF-Token in header.
But when I attempt to set it on angular nothing changes on request [headers are not set].
My login controller on ionic(angular):
var login = function(name, pw) {
return $q(function(resolve, reject) {
var data = "username="+name+"&password="+pw;
var config = {
headers : {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
}
}
$http.post('http://example.com/user/login.json', data, config)
.then(
function(response){
// success callback
storeUserCredentials(name + '.' + response.data.token, response.data.session_name, response.data.sessid);
storeUserRole(response.data.user.roles);
resolve('Login success.');
},
function(response){
// failure callback
//console.log('error '+response);
reject('Login Failed.');
}
);
});
};
My logout controller on ionic(angular):
var logout = function() {
var data = "username="+name+"&password="+pw;
var config = {
headers : {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
'X-CSRF-Token': token,
'Cookie':session_name + '=' + sessid
}
}
$http.post('http://example.com/user/logout.json', data, config)
.then(
function(response){
// success callback
destroyUserCredentials();
},
function(response){
// failure callback
destroyUserCredentials();
}
);
};
This technique works for me
I store the 'minimal' config object as a starting point. This object is created using the response from /services/session/token as the data in the following:
localStorageService.set('HTTP_CONFIG', {
headers: {
'Content-type': 'application/json',
'Accept': 'application/json',
'X-CSRF-Token': data
}
});
Contrary to many examples online, I find it unnecessary to set the cookies manually. In fact, attempting to set cookies often results in errors. In this example I'll use local storage to produce copies of the http config.
Next, I ascertain if I'm logged in or not.
var tokenConfig = localStorageService.get('HTTP_CONFIG');
tokenConfig.url = APP_CONFIG.REST_API + '/system/connect.json';
tokenConfig.method = 'POST';
tokenConfig.data = {};
$http(tokenConfig) ...
I simply carry forward in this manner, for instance:
var loginConfig = localStorageService.get('HTTP_CONFIG');
loginConfig.method = 'POST';
loginConfig.url = APP_CONFIG.REST_API + '/user/login';
loginConfig.data = { username: username, password: password };
$http(loginConfig) ...
I simply carry forward using the same 'minimal' http config object, adding properties as required. This has worked perfectly for me.

Resources