question

kharv avatar image
kharv asked keithryanwong Deactivated commented

OAuth 2.0 API Token Request - Receiving HTML Response Instead of Token

I'm currently attempting to request a token API token for my test merchant. I'm making the request to https://sandbox.dev.clover.com/. However, instead of a token, I'm receiving an HTML response and 200 OK response code (please see below for full request & response). Would someone mind explaining why I'm receiving the HTML response instead of a token?

Request:
curl --request GET \
--url 'https://apisandbox.dev.clover.com/oauth/authorize?client_id={id}' \
--header 'Content-Type: application/json'

Response:
<!DOCTYPE html>
<html>
<head>
<script>
function allowRedirect(path) {
var appWhitelist = [
'appmarket', 'authorizations', 'cashlog', 'closeout', 'discounts',
'employees', 'enterprise', 'home', 'inventory', 'orders', 'printers', 'reporting',
'setupapp', 'shifts', 'tabs', 'tips', 'transactions', 'wirelessmanager'
];

return path[0] === '/' && appWhitelist.some(function (app) {
return path.indexOf(app) === 1;
});
}

/**
* Attempt to extract a merchantId from a URL, falling back to sessionStorage.
* If an ID cannot be extracted, an empty string is returned.
*/
function extractMerchantId(path) {
var regex = /\/[a-z-]+\/m\/([a-z0-9]{13})(?:$|\/|\?)/i;
var match = path.match(regex);

return match ? match[1] : sessionStorage.getItem('merchantId') || '';
}

function redirectToDashboard() {
/**
* Do not attempt a redirect if we're in an iframe or this app is not allowed
* to redirect to the new web dashboard
*/
if (self !== top || !allowRedirect(location.pathname)) {
return;
}

var merchantId = extractMerchantId(location.href);
var isEnterpriseApp = location.pathname.indexOf('enterprise') > -1;

// If we are trying to go to the enterprise app, we know it's neither 'home' nor 'call-me' so
// redirect them to react with the current href as the webRedirectUrl. Or if the merchant
// is set to get the new dashboard, send them there too in that case. Enterprise refMerchantId
// is not entirely the same as a merchant hence the condition difference.
if (localStorage.getItem(merchantId + ':isNewDashboard') || isEnterpriseApp) {
var isHomeApp = location.pathname.indexOf('home') > -1;
var isCallMePage = location.pathname.indexOf('call-me') > -1;
var appendRedirectQueryParam = !isHomeApp || isCallMePage;
var urlExtra = appendRedirectQueryParam ? '?webRedirectUrl=' + location.href : '/m/' + merchantId;
var isLocalHost = location.href.indexOf('localhost') > -1;
var baseUrl = isLocalHost ? 'http://localhost:8080/dashboard' : '/dashboard';

location.href = baseUrl + urlExtra;
}
}

var hasBrowserStorage = localStorage && localStorage.getItem && sessionStorage && sessionStorage.getItem;

if (hasBrowserStorage) {
redirectToDashboard();
}

</script>
<script>
function shareSessionStorage() {
if (!sessionStorage.length) {
// get sessionStorage
localStorage.setItem('getSessionStorage', Date.now());
}

window.addEventListener('storage', event => {
if (event.key == 'getSessionStorage') {
// send sessionStorage
localStorage.setItem('sessionStorage', JSON.stringify(sessionStorage));
localStorage.removeItem('sessionStorage');
} else if (event.key == 'sessionStorage' && !sessionStorage.length) {
// set sessionStorage
var sharedStorage = JSON.parse(event.newValue);

for (var key in sharedStorage) {
sessionStorage.setItem(key, sharedStorage[key]);
}
}
});
}

var hasBrowserStorage = localStorage && localStorage.getItem && sessionStorage && sessionStorage.getItem;

if (hasBrowserStorage) {
shareSessionStorage();
}

</script>
<body>
Lot of meta an links inside.
</body>
</html>

SandboxMerchantOAuthAPI TokenAuth
10 |2000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

keithryanwong avatar image
keithryanwong Deactivated answered keithryanwong Deactivated commented
Hi @kharv,

Can you tell me where you're seeing instructions to make this specific request? You posted the same request URL in a previous question, but it is not from the OAuth documentation.

The overall process of OAuth involves 4 main steps:
1) Request merchant authorization
2) Receive an authorization code
3) Request an API token
4) Receive an API token

You seem to be at step one. Requesting merchant authorization involves having a merchant log in to their Clover Merchant account through the Clover Portal.

Your application, on seeing that its URI does not include the following query parameters– merchant_id={MERCHANT_ID}&client_id={APP_ID} &code={AUTHORIZATION_CODE}– should determine that the merchant has not logged in and redirected them to the Clover Portal using the following: https://sandbox.dev.clover.com/oauth/authorize?client_id={APP_ID}&client_secret={APP_SECRET} &code={AUTHORIZATION_CODE} where CLIENT_REDIRECT_URL is your application's url.

This URL is meant to be used to redirect your user to the Clover Portal, not to make a get request for the API token. After logging in, they will be redirected back to the CLIENT_REDIRECT_URL with the correct query parameters. Your application should parse the URI for the authorization code, which it will then use to make a get request to retrieve the API token, as outlined in step 3 in the documentation: https://docs.clover.com/build/oauth-2-0/

Best,
Keith
2 comments
10 |2000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

kharv avatar image kharv commented ·

Hi @keithryanwong,
Could the CLIENT_REDIRECT_URL be causing the issue for me? For this attribute I'm currently using valuehttp://localhost:8000 since I do not have a formal site URL. This is also the value I've set on my app in Settings > Web Configuration. You mentioned that my app should pares the URI for the auth code and use it to make a request for the API token. I appear to be stuck at 'Step 2' as I'm not able to receive anAUTHORIZATION_CODE after the below request is made.

curl -X GET \
'https://sandbox.dev.clover.com/oauth/authorize?client_id=BY2ZYS1RSKNA2&redirect_uri=http://localhost:8000' \
-H 'Cache-Control: no-cache' \
-H 'Content-Type: application/json' \

0 Likes 0 ·
keithryanwong avatar image keithryanwong kharv commented ·

Hi @kharv,

Apologies, I've been out of office. In accordance with our announcement, I need you to fill out the following google form before I can answer your question:

To provide more accurate and timely answers, we need more context about your semi-integration solution. Please fill out this information discovery form - https://goo.gl/forms/xIWnym9wwdZhiEYw1. Note that we will keep all your information private and will not disclose it to any other party.

Thanks,

Keith

0 Likes 0 ·
kharv avatar image
kharv answered keithryanwong Deactivated commented
Hi @keithryanwong,
No worries. I've filled out the information discovery form. Please let me know once you've reviewed it.
1 comment
10 |2000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

keithryanwong avatar image keithryanwong commented ·

Hi @kharv,

Thank you for filling that out. After reviewing your information, I've concluded that your questions belong in the App Market space of community and have moved it accordingly. Semi-integrations is for developers building point of sale solutions outside of Clover, but it seems like merchants using your app will still use the Clover as their main POS system. Please correct me if I've misunderstood.

I'm also not an expert on curl, but I don't believe that your program is actually following the redirect. It should not be an issue that your sandbox site is located at localhost.

Have you tried using -L or --location in order to follow the redirect?

Best,

Keith

0 Likes 0 ·

Welcome to the
Clover Developer Community