Standing up basic app to read out store data

I’m trying to build a Square app that, when installed by the Square user, reads out available store data to another platform. (This other platform will use the store data in combination with other data to make recommendations to the store owner, etc.)

I have never used Square’s API before and I am running in circles trying to get something basic running in the sandbox on localhost.

Most recently, I keep getting this error in the console:

GET https://squareupsandbox.com/oauth2/authorize?client_id=sandbox-XXXXXX-XXXXXXXXXXXXX&scope=MERCHANT_PROFILE_READ&state=9a0ahl&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fapi%2Fsquare%2Fcallback 400 (Bad Request)

This is my .env

NEXT_PUBLIC_SQUARE_APPLICATION_ID=sandbox-XXXXX-XXXXXXXXXXXXX
SQUARE_ACCESS_TOKEN=XXXXXXXXXXXXXXXXXXXXX
SQUARE_REDIRECT_URL=http://localhost:3000/api/square/callback

Here is /lib/squareClient.js:

const { Client } = require('square');

const squareClient = new Client({
  environment: 'sandbox', // or 'production' for live apps
  accessToken: process.env.SQUARE_ACCESS_TOKEN,
});

module.exports = squareClient;

here is /api/square.js

import { NextApiRequest, NextApiResponse } from 'next';
const squareClient = require('../lib/squareClient');

export default async function handler(req = NextApiRequest, res = NextApiResponse) {
  const { method } = req;

  switch (method) {
    case 'GET':
      // Example: Fetch merchant data
      try {
        const merchantsApi = squareClient.merchantsApi;
        const response = await merchantsApi.listMerchants();
        res.status(200).json(response.result);
      } catch (error) {
        res.status(500).json({ error: error.message });
      }
      break;

    default:
      res.setHeader('Allow', ['GET']);
      res.status(405).end(`Method ${method} Not Allowed`);
  }
}

here is /pages/api/square/callback.js

import { NextApiRequest, NextApiResponse } from 'next';

export default async function handler(req = NextApiRequest, res = NextApiResponse) {
  // Log all query parameters for debugging
  console.log('Callback received with query params:', req.query);

  const { code, state, error } = req.query;

  if (error) {
    console.error('Square OAuth error:', error);
    return res.redirect(`/?error=${encodeURIComponent(error)}`);
  }

  if (!code) {
    return res.redirect('/?error=No authorization code received');
  }

  try {
    // Log success and redirect
    console.log('Successfully received authorization code');
    res.redirect('/?success=true');
  } catch (err) {
    console.error('Callback error:', err);
    res.redirect(`/?error=${encodeURIComponent(err.message)}`);
  }
}

and here is /pages/index.js

import React, { useState } from 'react';
import Head from 'next/head';

export default function Home() {
  const [error, setError] = useState(null);

  const connectSquare = () => {
    try {
      const state = Math.random().toString(36).substring(7);
      
      // Build OAuth URL with minimal required parameters
      const authParams = new URLSearchParams({
        'client_id': process.env.NEXT_PUBLIC_SQUARE_APPLICATION_ID,
        'scope': 'MERCHANT_PROFILE_READ',
        'state': state,
        'response_type': 'code',
        'redirect_uri': `${window.location.origin}/api/square/callback`
      });

      const authUrl = `https://squareupsandbox.com/oauth2/authorize?${authParams.toString()}`;
      
      // Log the URL for debugging
      console.log('Redirecting to:', authUrl);
      
      // Redirect to Square's OAuth page
      window.location.href = authUrl;
    } catch (err) {
      setError(err.message);
      console.error('Error during Square connection:', err);
    }
  };

  return (
    <div>
      <Head>
        <title>Square Integration App</title>
        <meta name="description" content="Connect your Square account" />
      </Head>

      <main style={{ padding: '20px', maxWidth: '800px', margin: '0 auto' }}>
        <h1 style={{ marginBottom: '20px' }}>Square Integration App</h1>
        
        {error && (
          <div style={{ 
            padding: '10px', 
            marginBottom: '20px', 
            backgroundColor: '#fee', 
            border: '1px solid #f00',
            borderRadius: '4px'
          }}>
            Error: {error}
          </div>
        )}

        <div style={{ marginBottom: '20px' }}>
          <p>Click the button below to connect your Square account.</p>
          <p style={{ fontSize: '14px', color: '#666' }}>
            This will redirect you to Square's secure login page.
          </p>
        </div>

        <button 
          onClick={connectSquare}
          style={{
            padding: '10px 20px',
            fontSize: '16px',
            backgroundColor: '#006aff',
            color: 'white',
            border: 'none',
            borderRadius: '4px',
            cursor: 'pointer'
          }}
        >
          Connect Your Square Account
        </button>
      </main>
    </div>
  );
}

When I click the “Connect Your Square Account” button, I get the error at the top of the post.

Not sure where I’m going wrong.

:wave: I’m Square Dev AI, here to help answer your question!
Based on the information you’ve provided, the following documentation will help answer your question:

Additional Documentation

OAuth Walkthrough: Test Authorization with Web Server
https://developer.squareup.com/docs/oauth-api/walkthrough2
Get Started

If this documentation helped you find a solution, please check the box indicating that this reply solves the problem.
Otherwise one of our Developer Advocates will provide additional assistance shortly.

I believe the error is being caused by the redirect_uri. That is only for PKCE not the traditional OAuth. If you remove the redirect_uri does it work as expected? :slightly_smiling_face:

I get this in the console when I remove redirect_uri:

 GET
https://squareup.com/oauth2/authorize/assets/application-0906f056db09ab6d5c5562b5c588773d46189c069559f8dd324c24bf665d2db7.css
NS_ERROR_CORRUPTED_CONTENT

GET
https://squareup.com/oauth2/authorize/assets/application-3230aca0c83bed19ec685c47a1dc25c32ea8ca0dcd61c7907a0531bd2d0d5df4.js
NS_ERROR_CORRUPTED_CONTENT

Cookie “squareGeo” has been rejected because it is in a cross-site context and its “SameSite” is “Lax” or “Strict”. 2 application-0906f056db09ab6d5c5562b5c588773d46189c069559f8dd324c24bf665d2db7.css
The resource from “https://squareup.com/oauth2/authorize/assets/application-0906f056db09ab6d5c5562b5c588773d46189c069559f8dd324c24bf665d2db7.css” was blocked due to MIME type (“text/plain”) mismatch (X-Content-Type-Options: nosniff).
authorize
Cookie “squareGeo” has been rejected because it is in a cross-site context and its “SameSite” is “Lax” or “Strict”. 2 application-0906f056db09ab6d5c5562b5c588773d46189c069559f8dd324c24bf665d2db7.css
Cookie “squareGeo” has been rejected because it is in a cross-site context and its “SameSite” is “Lax” or “Strict”. 2 application-3230aca0c83bed19ec685c47a1dc25c32ea8ca0dcd61c7907a0531bd2d0d5df4.js
The resource from “https://squareup.com/oauth2/authorize/assets/application-3230aca0c83bed19ec685c47a1dc25c32ea8ca0dcd61c7907a0531bd2d0d5df4.js” was blocked due to MIME type (“text/plain”) mismatch (X-Content-Type-Options: nosniff).
authorize
Cookie “squareGeo” has been rejected because it is in a cross-site context and its “SameSite” is “Lax” or “Strict”. 2 application-3230aca0c83bed19ec685c47a1dc25c32ea8ca0dcd61c7907a0531bd2d0d5df4.js

Are you doing this all on the client side or do you have a server that’s calling Square APIs? You need server-side processing to utilize Square’s APIs. You’ll need to have this code written in PHP, ASP, Ruby, Java, or similar on the back end. This is code that runs behind the scenes on your hosting provider.

We do not allow API calls directly from the browser. This would expose your API credentials, which would allow anyone to gain access to your Square account. :slightly_smiling_face:

this is helpful - thanks. I was running this on localhost.

Is there a good “Idiot’s Guide to Making a Square App”?

This is my first time playing in this ecosystem and I am quite confused.

I am trying to make an app for your marketplace that, when installed, reads out store data to my business intelligence platform, so that it can make recommendations to the store owner based on store data and market data that my platform independently collects.

(Also, is there a recommended place to source Square developers? I am hoping to hire someone to complete this.)

We have General Requirement guide that you can use to see what’s required to build to our App Marketplace.

With Square Specialists you can build your business vision with expert developers. :slightly_smiling_face:

Thanks - I submitted the flow to get matched the other day but never heard back

When you say the other day do you mean a few days ago or like last week. I’m sure it’s just a matter of time before someone reaches out. :slightly_smiling_face:

It’s been over a week at this point

Okay, I’ll let the team know. :slightly_smiling_face: