When attempting to login any user, the following POST error results:
XMLHttpRequest cannot load https://api.stormpath.com/v1/applications/[APP_HREF]/login. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access. The response had HTTP status code 401.
In my server.js file, I have put the following:
var express = require('express');
var stormpath = require('express-stormpath');
var cors = require('cors');
var app = express();
app.use(stormpath.init(app, {
apiKey: {
id: 'xyz',
secret: 'abc' // Using the unsafe inline option for example purposes
},
application: {
href: `[APP_HREF]`
},
web: {
produces: ['application/json']
},
debug: 'info'
}));
app.use(cors({
origin: 'http://localhost:8080',
credentials: true
}));
app.post('/', stormpath.loginRequired, function (req, res) {
function writeError(message) {
res.status(400);
res.json({ message: message, status: 400 });
res.end();
}
});
app.on('stormpath.ready', function () {
var server = app.listen(process.env.PORT, function() {
try {
process.send('CONNECTED');
} catch(e) {}
});
});
In my login.jsx file, I have included:
login: function(e) {
e.preventDefault();
e.stopPropagation();
this.serverRequest = $.post('https://api.stormpath.com/v1/applications/[APP_HREF]/login',
{
"username": document.getElementById("email").value,
"password": document.getElementById("pass").value
}, function (result) {
console.log(result);
});
I also have saved my stormpath.yml file.
I'm not using React-Stormpath because I already created my views for Login and Registering. It looks like I only need to access the REST api with Stormpath, but I'm not sure what I need to add in order to get the API key validated.
On the actual login.jsx file, would I have to send the ID:SECRET pair as well as part of the POST request?
I see that in your login.jsx you are trying to post directly to the Stormpath REST API, but unfortunately that isn't possible yet. Instead you will make the post to your Express server, and in turn it will communicate with Stormpath.
You already have express-stormpath in your Express server, so you just need to post your login form to /login and Stormpath will take care of the rest :)
Let us know if you run into any issues! FYI, we will be adding a "serverless" feature soon, you can follow that here: http://ideas.stormpath.com/ideas/IAM-I-59
Related
I have a project where I set a cookie with universal-cookie.
cookies.set('auth-token', data);
I then have a fetch request:
const getMeals = async (date: Date) => {
let res= await fetch("http://127.0.0.1:5000/meals/", {
method: "POST",
credentials: "same-origin",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
date: date
}),
});
const data = await res.json();
console.log(data);
}
And a backend where it gets checked (NodeJs, ExpressJs):
module.exports = function(req, res, next){
const token = req.header('auth-token');
if(!token){
return res.status(401).json('Access denied!');
}
}
I see the cookie in my mozilla:
But I always get "Access denied!" -> that means the auth-token is not there...
I hardcoded the auth-token into the fetch and it worked.
I checked several websites and almost all stackoverflow posts on this theme. I also checked the fetch-api documentation, but I couldnt come up with a solution...
Both the client and the server are running on localhost.
I hope someone can help me with this topic.
UPDATE
Andreas suggested that I should either set the header(frontend) or look for cookie- instead of header-values(backend).
I decided to do the second approach.
Server.js
var cookieParser = require('cookie-parser')
const usersRouter = require('./routes/users'); //where auth.js gets imported
app.use(cors());
app.use(express.json());
app.use(cookieParser());
app.use('/users', usersRouter);
I tried changing the position of app.use(cookieParser()); to above all others - didnt help.
auth.js
module.exports = function(req, res, next){
const cookie = req.cookies['auth-token'];
console.log(cookie);
}
The problem I now have is that the cookie value is undefined even though the cookie gets displayed in FireFox.
I tried to do the steps of this post, but this doesnt work afterwards I went to their official documentation and found nothing.
I also stumbled upon this one, which makes me think that something is wrong in the frontend...
Frontend-File where I set the cookie:
import Cookies from 'universal-cookie';
const cookies = new Cookies();
const login = async () => {
let res= await fetch("http://127.0.0.1:5000/users/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: (e.target as HTMLFormElement).email.value,
password: (e.target as HTMLFormElement).password.value,
}),
});
const data = await res.json()
if(res.status === 200){
cookies.set('auth-token', data);
setUserId((jwt_decode(data) as any)._id);
navigate("/");
}else{
alert(data);
}
}
Does someone have an idea?
I could fix the problem with the help of a friend. I had to add "proxy": "http://localhost:5000/" to my package.json in my React-Project, because the port is important for the cookie so localhost:5000 and localhost:3000 are not the same for it. I could also remove the app.use(cors()) from my NodeJs-Project, because of it.
I would suggest you run your front end on http://127.0.0.1:3000. If you are already doing that then you have to call fetch with credentials options set to include.
This is because unless fetch() is called with the credentials option set to include, fetch():
won't send cookies in cross-origin requests
won't set any cookies sent back in cross-origin responses
As of August 2018, the default credentials policy changed to same-origin. Firefox was also modified in version 61.0b13)
I'm trying to write and read cookies and falling into a problem below.
This is my basic server side:
server.js
const app = express();
app.use(cors());
app.use(cookieParser());
import routes from '...';
app.use("/foo", routes);
app.listen(8888);
routes.js
const routes = express.Router();
routes.post('/', (req, res) => {
res.cookie("myFoo", "abcd");
res.send("Cookie added");
}
});
routes.get('/', (req, res) => {
res.send(req.cookies.myFoo);
}
});
export default routes;
And my client side at "http://localhost:3000".
I do two HTTP request
POST http://localhost:8888/foo
GET http://localhost:8888/foo
And get the response exactly what I expected abcd. Also, the cookie exists in the browser tab Application > Cookies too.
The problem cases when axios is used in the client.
const api = axios.create({
baseURL: "http://localhost:8888/foo"
});
async function setCookie(object) {
return api.post("/", object)
.then((res) => {
return res;
});
}
function getCookie() {
return api.get("/")
.then((res) => {
return res;
});
}
setCookie({})
.then((res) => {
getCookie();
})
The api.post() run usually and the header response Set-Cookie is correct. But cookies in the browser tab Application > Cookies are empty. Also, api.get() get the undefined.
I did try to move res.cookie() or the set cookie job in server side to GET route it WORKS on both HTTP and axios
routes.get('/', (req, res) => {
res.cookie("myFoo", "abcd");
});
tldr: Set cookie in HTTP POST method work fine but when client use axios to call so it causes problems.
Can you show me why this happened? And which code part went wrong that caused me into this?
Cookies are only used in cross-origin Ajax requests when:
The client asks to use them
The server grants permission to use them cross origin
So you need to change the client side code to ask for them:
const api = axios.create({
baseURL: 'http://localhost:8888/',
withCredentials: true,
});
And the server code to grant permission (note that you can't use credentials at the same time as the wildcard for origins).
app.use(cors({
origin: 'http://localhost:3000',
credentials: true
}));
I'm using the following code in a simple slash command app to handle OAuth for public distribution of my app:
const express = require("express");
const bodyParser = require("body-parser");
const fetch = require("node-fetch")
require('dotenv').config();
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
// App installation handling
app.get("/auth", async (req, res) => {
if (!req.query.code) {
console.log("Access denied!");
return;
}
var data = {form: {
client_id: process.env.SLACK_CLIENT_ID,
client_secret: process.env.SLACK_CLIENT_SECRET,
code: req.query.code,
redirect_uri: "https://6c0c-35-20-201-50.ngrok.io/auth"
}};
console.log(req.query.code);
// Send received code back to Slack and get Oauth2 access token
const config = {
method: "POST",
body: data,
headers: {'Content-type': 'application/x-www-form-urlencoded'}
};
console.log("We got something!");
try {
const slack_oauth_response = await fetch("https://slack.com/api/oauth.v2.access", config);
console.log("Access token granted!");
console.log(JSON.stringify(slack_oauth_response.access_token));
} catch (e) {
console.error(e);
}
res.sendStatus(200);
})
When I try using the Add to Slack button, I get a timeout error. My log results will look like this:
PS D:\Documents\SlackRegApp> node local_testing.js
1007612862405.3292595223126.481b3e25d2c29dc80af7dc21bcb84a8bc19c28ddec155a429c6651105903902f
We got something!
Access token granted!
undefined // where the access token should be
If I go ahead and just log the entirety of slack_oauth_response, it looks like this:
{"size":0, "timeout":0}
When I try to install the app via cURL, it works, like below:
curl -F code=1007612862405.3292595223126.481b3e25d2c29dc80af7dc21bcb84a8bc19c28ddec155a429c6651105903902f -F client_id=**SLACK_CLIENT_ID** -F client_secret=**SLACK_CLIENT_SECRET** https://slack.com/api/oauth.v2.access
Hoping for some help here, thanks!
I just used the Slack WebClient API to access the oauth.v2.access method instead of trying to make my own HTTP request.
Back-end on: node.js, express. Other modules used: body-parser, request.
I am trying to fetch track ID from Spotify Search API.
A user makes a POST request. The request is fed to the server.
The server makes GET request to the endpoint.
The endpoint returns data.
The data is parsed to JSON.
Problem: Upon parsing, following error is logged into the terminal.
{ error: { status: 400, message: 'Bad search type field tracks' } }
Code to focus on:
request({
url: searchUrl,
headers: {
"Authorization": token
}
}, function(err, res) {
if (res) {
var data = JSON.parse(res.body);
// var spotifyTrackIdAppJs00 = data.tracks.items[0].id;
console.log(data);
// console.log(trackId);
}
)
Complete app.js code:
// It is a nodejs, expressjs project.
const express = require("express");
// 'body-parser' is used to access tags from the html file. We'll be using it to access queryValue.
const bodyParser = require("body-parser");
// request package; to fetch data from search endpoint.
const request = require("request");
// This app constant is created to be able to access the menthods available in 'express' package.
const app = express();
// 'urlencoded' helps access html data. Other data formats could JSON etc.
// body-parser required as to exclusively define "extended: true" although this is no use to us.
app.use(bodyParser.urlencoded({
extended: true
}));
// This sets a static directory to look for source files like css, js, img. These file links are mentioned in html or ejs files.
// A folder named 'public' has to be in the same directory as "app.js". The source files are stored here.
app.use(express.static("public"));
// ejs view engine has been used to use app.js variables into the output ejs file.
app.set('view engine', 'ejs');
// Variable(s) to store the data fetched from API endpoint.
var data = "";
// The page to load when the browser (client) makes request to GET something from the server on "/", i.e., from the homepage.
// This GET request is made as soon as the homepage url is entered in the address bar od browser, automatically.
app.get("/", function(req, res) {
res.sendFile(__dirname + "/index.html");
});
// The data that server should POST when the POST request is sent by the client, upon entering the search queryValue, in the search bar (form).
app.post("/", function(req, res) {
// The user input query. We are using body-parser package here.
const query = req.body.queryValue;
// Follow procedure here to get access_token and refresh_token: https://benwiz.com/blog/create-spotify-refresh-token/
const access_token = {access_token};
const token = "Bearer " + access_token;
var searchUrl = "https://api.spotify.com/v1/search?q=" + query + "&type=tracks&limit=4";
request({
url: searchUrl,
headers: {
"Authorization": token
}
}, function(err, res) {
if (res) {
var data = JSON.parse(res.body);
// var spotifyTrackIdAppJs00 = data.tracks.items[0].id;
console.log(data);
// console.log(trackId);
}
// res.render("results", {
// spotifyTrackIdEjs00: spotifyTrackIdAppJs00
// });
// console.log("Value to be used in rendered file: " + spotifyTrackIdAppJs00);
})
});
// Starting the server. Should this be placed at the top of all other commands?
app.listen(3000, function() {
console.log("Server is running on port 3000.")
});
Helpful Resources:
Follow the steps here to get the access_token: https://benwiz.com/blog/create-spotify-refresh-token/
Understand parameters here: https://developer.spotify.com/documentation/web-api/reference/#category-search
Spotify Web Console to understand the JSON arrangement: https://developer.spotify.com/console/get-search-item/
I am an absolute beginner. Please teach me like I'm five. I would be highly grateful to you.
Your code looks fine, but you have one typo that is messing up all. This one:
var searchUrl = "https://api.spotify.com/v1/search?q=" + query + "&type=tracks&limit=4";
The Spotify's API's parameter type have the following valid valued:
album , artist, playlist, track, show and episode.
On your searchUrl, you are using tracks (plural) instead of track, so it should be:
var searchUrl = "https://api.spotify.com/v1/search?q=" + query + "&type=track&limit=4";
For the future: the HTTP's 400 code means "Bad Request", meaning that server is telling you that something is being sent wrong on the request. When you get that kind of error response, usually is good to double check the required params/body of the API you are consuming and their accepted values
I am trying to trigger an express.js route from the front-end via an ajax call. Once the route is called it redirects to an external redirect to another domain. Every time I run this route I run into a CORs preflight error.
I imagine the ideal workflow would look something like this:
User clicks on the subscription button.
An AJAX (Jquery) call is sent to the express route (app.get('/shopify/new-charge')).
The express route runs.
The external redirect is triggered and the user is sent to the other domain.
Through my research I think the issue is with the response coming back from the back-end to the front end.
I have tried implementing the following:
modifying the AJAX call
npm CORS in the server.js
adding headers to the server.js
adding headers to the ajax
adding headers to the redirect
adding a status to the redirect ( res.redirect(301, 'https://external-url.com' )
adding in next() after the res.redirect()
whitelisting the origin and the origin with the route
However, I was successful in resolving this conflict by wrapping my button with a form, and eliminating the AJAX call, but I would like to know if this is possible via an AJAX call from the front end.
Front End Ajax Call
activateSubscriptionButton.addEventListener('click', function () {
var newChargeUrl = "/shopify/new-charge;
$.ajax({
type: "GET",
url: newChargeUrl,
data: {"shop" : test.com},
success: function (result) {
console.log('Success - Paid');
},
error: function (jqXHR, exception) {
console.log('Error - No Paid');
console.log('jqXHR :', jqXHR);
},
});
}, false);
Express.js Route
app.get("/shopify/new-charge", function (req, res, next) {
const shop_domain = req.query.shop;
const shopRequestUrl = 'https://' + shop_domain + '/admin/api/2019-04/recurring_application_charges.json';
const newCharge = {
"recurring_application_charge": {
"name": "Professional Plan",//
"price": 4.99,
"return_url": forwardingAddress + "\/shopify\/billing\/activate?shop=" + encodeURIComponent(shop_domain),
"test": true,
}
};
request.post(shopRequestUrl,
{
headers: {
'X-Shopify-Access-Token': access_token,
},
json: newCharge
}, function (error, response, body) {
if (error) {
console.error('Error has occurred with charge: ', error);
return
}
else {
// Redirect User To External Confirmation Page//
res.redirect('https://external-url.com/');
}
})
else {
res.send('Error: No shop_domain.');
}
});
Server.js
var express = require("express");
var app = express();
var bodyParser = require("body-parser");
const forwardingAddress = process.env.ngrok_forwarding_address;
app.use(express.static("public"));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(bodyParser.text());
require("./controllers/shopify")(app);
require("./controllers/billing")(app);
// Setting up port and requiring models for syncing
var PORT = process.env.PORT || 3000;
app.listen(PORT, function () {
console.log("Server listening on: http://localhost:" + PORT);
});
Below is the error I receive when I run the above code:
OPTIONS: https://external-url.com 404
Access to XMLHttpRequest at 'https://external-url.com' (redirected from 'https://local.ngrok.com/shopify/new-charge?shop=test.com') from origin 'https://local.ngrok.com' has been blocked by CORS policy: Response to preflight request doesnt pass access control check: No 'Access-Control-Allow_Origin' header is present on the requested resource.
Is there a way to accomplish my goal by modifying the existing code presented above?
You are really missing out on a fundamental feature of Shopify here. With regards to your App, go into your App setup in your Partner account and for that App create an App Proxy call. The endpoint you create is then what you call from the front-end with your JS code. Shopify ensures security, and all your CORS problems go away. This is why the App Proxy exists, to allow front-end calls to be securely made to back-end Apps.
TL:DR; Your front-end pattern is doomed, and you should re-factor to use secure App Proxy.