Shopify OAuth verification failing with 'Request not from Shopify' error message

I’m working on creating a Shopify app and trying to get an access token through OAuth. I keep getting an error that says the request isn’t from Shopify.

My authorization file (auth.php):

<?php

// Configuration settings
$store_name = "my-test-shop";
$client_id = "abc123def456ghi789jkl";
$permissions = "read_products,write_orders";
$callback_url = "http://localhost/myapp/token_handler.php";

// Create authorization URL
$auth_url = "https://" . $store_name . ".myshopify.com/admin/oauth/authorize?client_id=" . $client_id . "&scope=" . $permissions . "&redirect_uri=" . urlencode($callback_url);

// Send user to Shopify
header("Location: " . $auth_url);
exit();

After clicking install, it sends me back to my callback URL with parameters like code, hmac, shop, etc. But my token handler keeps rejecting it.

My token handler (token_handler.php):

<?php

// App configuration
$store_name = "my-test-shop";
$client_id = "abc123def456ghi789jkl";
$client_secret = "xyz789abc123def456";
$auth_code = $_GET["code"];
$request_timestamp = $_GET["timestamp"];
$request_signature = $_GET["signature"];

// Build signature string for verification
$signature_string = $client_secret . "code=" . $auth_code . "shop=" . $store_name . ".myshopify.comtimestamp=" . $request_timestamp;

// Verify the request came from Shopify
if (md5($signature_string) === $request_signature) {
    
    // Prepare token request
    $token_params = array(
        "Content-type" => "application/json",
        "client_id" => $client_id,
        "client_secret" => $client_secret,
        "code" => $auth_code
    );
    
    // Make API call to get token
    $api_response = make_shopify_request(NULL, $store_name, "/admin/oauth/access_token", $token_params, 'POST');
    
    // Parse the response
    $response_data = json_decode($api_response['response'], TRUE);
    $access_token = $response_data['access_token'];
    
    echo $access_token;
    
} else {
    die('This request is NOT from Shopify!');
}

I’ve tried hosting it on different servers including HTTPS ones but the signature verification always fails. The MD5 hash I generate never matches what Shopify sends. What could be wrong with my signature verification logic?

yeah your signature verification is totally wrong there. shopify dosent send signature and timestamp params anymore, they send hmac instead. you need to grab the hmac from $_GET[‘hmac’] and verify it against all the other query params using hash_hmac with sha256. also dont hardcode the store name, use $_GET[‘shop’] from the callback. thats probably why its failing

Your verification method is outdated - Shopify deprecated the signature/timestamp approach years ago. The callback parameters you’re looking for don’t exist anymore, which explains why your verification always fails.

I ran into this same wall when working with legacy tutorials. Modern Shopify OAuth uses HMAC-SHA256 verification instead of MD5 signatures. You need to collect all query parameters except ‘hmac’ and ‘signature’, sort them alphabetically, create a query string, then verify against the hmac parameter using hash_hmac(‘sha256’, $query_string, $client_secret).

Also remove the hardcoded store name completely - use $_GET[‘shop’] from the callback instead. The shop parameter contains the actual domain that initiated the OAuth flow, and this needs to match exactly for the verification to work. Your current approach with hardcoded values will fail even with correct HMAC verification since the shop domains won’t align properly.

I had this exact issue when I first started with Shopify OAuth and it drove me crazy for hours. The problem is that Shopify changed their authentication flow and no longer uses the signature parameter you’re checking for. Instead, they use HMAC verification with a different approach.

You need to verify the HMAC parameter that comes back in the callback, not a signature parameter. The HMAC is calculated using all the query parameters except the HMAC itself, sorted alphabetically and joined with ampersands. Then you hash that string with your client secret using SHA256, not MD5.

Also, make sure you’re getting the shop parameter from the callback URL rather than hardcoding your store name, since the actual shop domain gets passed back in the response. I wasted a lot of time with hardcoded values that didn’t match what Shopify was actually sending. Once I switched to proper HMAC verification using the shop parameter from the callback, everything worked perfectly.