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.