Dealing with CORS Errors in Blockstack Auth and React

I’ve been working on building the simple Hello Blockstack app in React, but it seems no matter what I do, I can’t get Blockstack auth to work.

I followed the quick start instructions here:

I wired up the sign in button using a React component, but the redirectToSignIn function is always coming back as undefined.

Has anyone made this work in React and willing to share an example?

Thanks!

The following import statement worked for me in react:
import * as blockstack from 'blockstack'
But I am now trying to enable CORS in the react development server, because blockstack tries to fetch the manifest.json from your application during the sign-in process and it fails with the following error:

Failed to load http://localhost:3000/manifest.json: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://localhost:8888’ is therefore not allowed access. If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.
main.js:58289 TypeError: Failed to fetch
main.js:209197 2017-11-09T11:07:10.550-0500 ERROR auth/store/auth.js: loadAppManifest: error URI request couldn’t be completed

Vuejs seems to be a better option as we can customize the development server directly to add CORS support.

1 Like

Thanks @muneebm! I had actually just figured that out as well. I’ll play around in React to see if I can get the CORS headers working on the dev server. If not, I’ve been wanting to experiment with Vue.js, so this might be a good reason to. :grinning:

1 Like

You can use webpack’s built in server to adjust CORS settings. Add the code below into your root as webpack.config.js The config below should work out of the box for react-create-app

Edit package.json – "start": "weback-dev-server"

Then run npm run start

webpack.config.js:

const path = require('path');
const webpack = require('webpack');

// copy manifest.json to the path: 'public/build'
// this will allow for the authRequest to see the file at www.example.com/manifest.json
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ManifestAssetPlugin = new CopyWebpackPlugin([ { from: 'public/manifest.json', to: 'manifest.json' } ]);
const IconAssetPlugin = new CopyWebpackPlugin([ { from: 'public/favicon.ico', to: 'favicon.ico' } ]);
const IconMobileAssetPlugin = new CopyWebpackPlugin([ { from: 'public/mobile-icon.png', to: 'mobile-icon.png' } ]);

const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackPluginConfig = new HtmlWebpackPlugin({
  template: './public/index.html',
  filename: 'index.html',
  inject: 'body'
});

module.exports = {
  entry: './src/index.js',
  target: 'web',
  output: {
    path: path.resolve('public/build'),
    // filename: 'index_bundle.js',
    filename: 'index.js',
  },
  devServer: {
    historyApiFallback: true,
    watchOptions: { aggregateTimeout: 300, poll: 1000 },
    headers: {
      "Access-Control-Allow-Origin": "*",
      "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
      "Access-Control-Allow-Headers": "X-Requested-With, content-type, Authorization",
    },
  },
  module: {
    rules: [
      { test: /\.json$/, use: 'json-loader' },
      { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/,
        query: {
          presets: ['es2015', 'react']
        }
      },
      { test: /\.jsx$/, loader: 'babel-loader', exclude: /node_modules/ },
      {
        test: /\.(eot|woff|woff2|ttf|svg|png|jpe?g|gif)(\?\S*)?$/,
        loader: 'file-loader!url-loader',
      },
      { test: /\.css$/, loader: 'style-loader!css-loader' }
    ]
  },
  plugins: [HtmlWebpackPluginConfig, ManifestAssetPlugin, IconAssetPlugin, IconMobileAssetPlugin]
}
3 Likes

This is great, thanks!

Hopefully this will make your life easier to handle the sign in. It’s a sign in component.


https://www.npmjs.com/package/blockstack-signin-btn

I also have a working demo here:

4 Likes

@keith

I’ve actually been using your boilerplate for a few days now. Thanks so much for putting that together. It’s sped thing up significantly for me to have a starting point for both auth and putting/reading files.

Thanks!

2 Likes

Hey @vinniejames,

Thanks for posting this fix. Unfortunately, I can’t seem to get the app to be served properly. I’m getting an error where it’s not building a module because of a syntax error. However, we do not get this syntax error when running with the react-scripts module, so we think it’s a problem in recognizing es2015 or react syntax. Here’s the error we’re getting. The webpack.config.js file we use is the same as the one you posted.

> webpack-dev-server

Project is running at http://localhost:8080/
webpack output is served from /
404s will fallback to /index.html
Hash: 1b751446c506ef55fe54
Version: webpack 3.8.1
Time: 3940ms
                               Asset       Size  Chunks                    Chunk Names
88f4e49da83adf2062b9d18d1e0b935f.svg    3.61 kB          [emitted]         
                            index.js    3.59 MB       0  [emitted]  [big]  main
                          index.html    1.64 kB          [emitted]         
                       manifest.json  317 bytes          [emitted]         
                         favicon.ico    3.87 kB          [emitted]         
  [51] ./node_modules/react/index.js 190 bytes {0} [built]
  [73] ./node_modules/url/url.js 23.3 kB {0} [built]
 [217] multi (webpack)-dev-server/client?http://localhost:8080 ./src/index.js 40 bytes {0} [built]
 [218] (webpack)-dev-server/client?http://localhost:8080 7.95 kB {0} [built]
 [224] ./node_modules/strip-ansi/index.js 161 bytes {0} [built]
 [226] ./node_modules/loglevel/lib/loglevel.js 7.86 kB {0} [built]
 [227] (webpack)-dev-server/client/socket.js 1.05 kB {0} [built]
 [229] (webpack)-dev-server/client/overlay.js 3.73 kB {0} [built]
 [234] (webpack)/hot nonrecursive ^\.\/log$ 170 bytes {0} [built]
 [236] (webpack)/hot/emitter.js 75 bytes {0} [built]
 [237] ./src/index.js 677 bytes {0} [built]
 [241] ./node_modules/react-dom/index.js 1.36 kB {0} [built]
 [250] ./src/index.css 1.01 kB {0} [built]
 [253] ./src/App.js 4.95 kB {0} [built]
 [562] ./src/registerServiceWorker.js 4.03 kB {0} [built]
    + 548 hidden modules

WARNING in ./node_modules/blockstack-storage/node_modules/ajv/lib/async.js
119:15-28 Critical dependency: the request of a dependency is an expression
 @ ./node_modules/blockstack-storage/node_modules/ajv/lib/async.js
 @ ./node_modules/blockstack-storage/node_modules/ajv/lib/ajv.js
 @ ./node_modules/blockstack-storage/lib/inode.js
 @ ./node_modules/blockstack-storage/lib/index.js
 @ ./node_modules/blockstack/lib/storage/index.js
 @ ./node_modules/blockstack/lib/index.js
 @ ./src/App.js
 @ ./src/index.js
 @ multi (webpack)-dev-server/client?http://localhost:8080 ./src/index.js

WARNING in ./node_modules/blockstack-storage/node_modules/ajv/lib/compile/index.js
13:21-34 Critical dependency: the request of a dependency is an expression
 @ ./node_modules/blockstack-storage/node_modules/ajv/lib/compile/index.js
 @ ./node_modules/blockstack-storage/node_modules/ajv/lib/ajv.js
 @ ./node_modules/blockstack-storage/lib/inode.js
 @ ./node_modules/blockstack-storage/lib/index.js
 @ ./node_modules/blockstack/lib/storage/index.js
 @ ./node_modules/blockstack/lib/index.js
 @ ./src/App.js
 @ ./src/index.js
 @ multi (webpack)-dev-server/client?http://localhost:8080 ./src/index.js

WARNING in ./node_modules/blockstack-storage/node_modules/ajv/lib/async.js
96:20-33 Critical dependency: the request of a dependency is an expression
 @ ./node_modules/blockstack-storage/node_modules/ajv/lib/async.js
 @ ./node_modules/blockstack-storage/node_modules/ajv/lib/ajv.js
 @ ./node_modules/blockstack-storage/lib/inode.js
 @ ./node_modules/blockstack-storage/lib/index.js
 @ ./node_modules/blockstack/lib/storage/index.js
 @ ./node_modules/blockstack/lib/index.js
 @ ./src/App.js
 @ ./src/index.js
 @ multi (webpack)-dev-server/client?http://localhost:8080 ./src/index.js

ERROR in ./src/ProfilePage.jsx
Module build failed: SyntaxError: Unexpected token (26:6)

  24 |     render() {
  25 |       return (
> 26 |       <div>
     |       ^
  27 |             <h1>{this.props.userName} BlockTweet Profile</h1>
  28 |             <InputBox 
  29 |             tweetList = {this.state.userTweets} 

 @ ./src/App.js 24:19-47
 @ ./src/index.js
 @ multi (webpack)-dev-server/client?http://localhost:8080 ./src/index.js
Child html-webpack-plugin for "index.html":
     1 asset
       [0] ./node_modules/html-webpack-plugin/lib/loader.js!./public/index.html 1.99 kB {0} [built]
       [1] ./node_modules/lodash/lodash.js 540 kB {0} [built]
       [2] (webpack)/buildin/global.js 488 bytes {0} [built]
       [3] (webpack)/buildin/module.js 495 bytes {0} [built]
webpack: Failed to compile.

We’re trying not to switch away from developing using React, so any help regarding this error will be much appreciated

Here is another solution. A basic starter kit for building Blockstack apps with React by @benoror

2 Likes

It sounds more like a problem with your React code? I might try rewriting your render method to double check for errors. As @muneebm said, the starter kits are helpful too. I used this one and pulled out the needed components

1 Like

Thanks for your response! The code compiles and is rendered fine when run with react-scripts, so it’s unlikely to be a syntax error in the React code, but we’ll double check. It might be a babel issue so we’re investigating that.

did you make sure all the dependencies called in the webpack file are installed?

Hey @vinniejames, just (re)installed all dependencies in the webpack file and still get the same error I posted above :frowning:

The changes you suggested were literally the only things we changed from the files created from create-react-app, were there any other dependencies or modules that were needed for the webpack.config.js changes to work properly?

Managed to get the server to work! There was a problem in the .babelrc file which was missing!

1 Like

Unfortunately, I am also running into a CORS Error when I want to deploy the app to netlify. In development everything works fine. Does anyone have an idea what I am missing here? I am a Webpack newbie… sorry.

Thanks so much for helping out :pray: .

This is my webpack.config.js file :

const path = require('path');
const webpack = require('webpack');

// copy manifest.json to the path: 'public/build'
// this will allow for the authRequest to see the file at www.example.com/manifest.json
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ManifestAssetPlugin = new CopyWebpackPlugin([ { from: 'src/assets/manifest.json', to: 'manifest.json' } ]);
const IconAssetPlugin = new CopyWebpackPlugin([ { from: 'src/images/icon-192x192.png', to: 'icon-192x192.png' } ]);
const UglifyEsPlugin = require('uglify-es-webpack-plugin');
const UglifyEsPluginConfig = new UglifyEsPlugin({
	mangle: {
		reserved: [
            	'Buffer',
                    'BigInteger',
                    'Point',
                    'ECPubKey',
                    'ECKey',
                    'sha512_asm',
                    'asm',
                    'ECPair',
                    'HDNode'
            ]
    }
})


const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackPluginConfig = new HtmlWebpackPlugin({
  template: './src/index.html',
  filename: 'index.html',
  inject: 'body'
});

module.exports = {
  entry: './src/index.js',
  target: 'web',
  output: {
path: path.resolve('public/build'),
filename: 'index_bundle.js',
  },
  devServer: {
historyApiFallback: {
  disableDotRule: true
},
watchOptions: { aggregateTimeout: 300, poll: 1000 },
headers: {
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
  "Access-Control-Allow-Headers": "X-Requested-With, content-type, Authorization",
},
  },
  module: {
rules: [
  { test: /\.json$/, use: 'json-loader' },
  { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ },
  { test: /\.jsx$/, loader: 'babel-loader', exclude: /node_modules/ },
  {
    test: /\.(eot|woff|woff2|ttf|svg|png|jpe?g|gif)(\?\S*)?$/,
    loader: 'file-loader!url-loader',
  },
  { test: /\.css$/, loader: 'style-loader!css-loader' }
]
  },
  plugins: [
	HtmlWebpackPluginConfig,
	ManifestAssetPlugin,
	IconAssetPlugin,
	UglifyEsPluginConfig
 ]
}

When deploying to netlify, there are a couple things you have to do differently than when you deploy to somewhere like Heroku:

  1. In your public folder, create a file called “_headers”
  2. In that same folder create a file called “_redirects”

The CORS issue is tied to the _headers file, an issue you haven’t run into but you would is tied to the _redirects file.

In the _headers file, drop in this code:

/index.html
  Access-Control-Allow-Origin: *
 Access-Control-Allow-Headers: "X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding"
 Access-Control-Allow-Methods: "POST, GET, OPTIONS, DELETE, PUT"
/manifest.json
  Access-Control-Allow-Origin: *
 Access-Control-Allow-Headers: "X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding"
 Access-Control-Allow-Methods: "POST, GET, OPTIONS, DELETE, PUT"

Then, in the _redirects file, drop in this:

/* /index.html 200

That should take care of your issues. Good luck!

2 Likes

Justin, you are the man! Thanks so much! Works like a charm. I had the “_redirects” file, but haven’t heard yet about the “_headers”. Made my day :facepunch:

1 Like

Hi all, I am getting the following error
Access to fetch at ‘https://www.milalabs.org/manifest.json’ from origin ‘http://localhost:8888’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.

Any ideas that can help me? I am new to this.

Here is my webpack.config.js file
require(‘babel-polyfill’);
const path = require(‘path’);
const webpack = require(‘webpack’);

const CopyWebpackPlugin = require(‘copy-webpack-plugin’);

const ManifestAssetPlugin = new CopyWebpackPlugin([
{ from: ‘src/assets/manifest.json’, to: ‘manifest.json’ },
]);
const IconAssetPlugin = new CopyWebpackPlugin([
{ from: ‘src/images/milalogo.jpg’, to: ‘icon-192x192.png’ },
]);

const HtmlWebpackPlugin = require(‘html-webpack-plugin’);

const HtmlWebpackPluginConfig = new HtmlWebpackPlugin({
template: ‘./src/index.html’,
filename: ‘index.html’,
inject: ‘body’,
});

module.exports = {
entry: [‘babel-polyfill’, ‘./src/index.js’],
target: ‘web’,
output: {
path: path.resolve(‘public/build’),
filename: ‘index_bundle.js’,
},
devServer: {
historyApiFallback: true,
watchOptions: { aggregateTimeout: 300, poll: 1000 },
headers: {
‘Access-Control-Allow-Origin’: '’,
‘Access-Control-Allow-Methods’: ‘GET, POST, PUT, DELETE, PATCH, OPTIONS’,
‘Access-Control-Allow-Headers’:
‘X-Requested-With, content-type, Authorization’,
},
disableHostCheck: true,
},
module: {
rules: [
{
test: /config.json$/,
loader: ‘special-loader’,
type: ‘javascript/auto’,
},
{
test: /.(js|jsx)$/,
exclude: /(node_modules|bower_components)/,
loader: ‘babel-loader’,
},
{
test: /.(eot|woff|woff2|ttf|svg|png|jpe?g|gif)(?\S
)?$/,
loader: ‘url-loader’,
},

  { test: /\.css$/, loader: 'style-loader!css-loader' },
],

},
plugins: [HtmlWebpackPluginConfig, ManifestAssetPlugin, IconAssetPlugin],
};

Hi All, I was able to find the fix in this website, if anyone else has the same error

https://www.w3.org/wiki/CORS_Enabled#For_Apache