I have reproduced the issue on the latest CLI version.
Yes, I am on the latest version
I have searched existing posts and this report is not a duplicate.
Yes, this isn’t a duplicate
In which of these areas are you experiencing a problem?
PHP Library
Expected behavior
Clicking in my app to navigate to that URL within the iframe.
Actual behavior
I have set it up using Laravel for an App Home app.The only problem I have is navigation within the iframe.When I use Polaris component I get the following error: Embedded app without id_token. Redirect to the patch ID token page to obtain a new token using the provided response.
But when I use the everything works like expected.My thought was that the App Bridge would intercept the link clicks and add the required GET params / headers.But it doesn’t seem to work.
I’d love to hear what you think it is!
Reproduction steps
Follow the shopify-app-php instructions for Laravel.
Then wrap your routes in this middleware:
<?php
namespace App\Http\Middleware;
use App\Http\Responses\ShopifyResponse;
use App\Models\ShopifyAccessToken;
use Closure;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\Request;
use Shopify\App\ShopifyApp;
use Symfony\Component\HttpFoundation\Response;
class VerifyShopifyRequest
{
public function handle(Request $request, Closure $next): Response
{
$shopify = app(ShopifyApp::class);
$req = [
"method" => $request->method(),
"headers" => $request->headers->all(),
"url" => $request->fullUrl(),
"body" => $request->getContent(),
];
$result = $shopify->verifyAppHomeReq(
$req,
appHomePatchIdTokenPath: "/auth/patch-id-token",
);
if (!$result->ok) {
return ShopifyResponse::from($result->log, $result->response);
}
try {
$accessToken = ShopifyAccessToken::query()
->where("shop", $result->shop)
->where("access_mode", "offline")
->firstOrFail();
$refreshResult = $shopify->refreshTokenExchangedAccessToken([
"shop" => $accessToken->shop,
"accessMode" => $accessToken->access_mode,
"token" => $accessToken->token,
"scope" => $accessToken->scope,
"refreshToken" => $accessToken->refresh_token,
"expires" => $accessToken->expires,
"refreshTokenExpires" => $accessToken->refresh_token_expires,
]);
if (!$refreshResult->ok) {
return ShopifyResponse::from(
$refreshResult->log,
$refreshResult->response,
);
}
if (isset($refreshResult->accessToken)) {
$accessToken->update([
"token" => $refreshResult->accessToken->token,
"scope" => $refreshResult->accessToken->scope,
"refresh_token" =>
$refreshResult->accessToken->refreshToken,
"expires" => $refreshResult->accessToken->expires,
"refresh_token_expires" =>
$refreshResult->accessToken->refreshTokenExpires,
]);
}
} catch (ModelNotFoundException) {
$exchangeResult = $shopify->exchangeUsingTokenExchange(
accessMode: "offline",
idToken: $result->idToken,
invalidTokenResponse: $result->newIdTokenResponse,
);
if (!$exchangeResult->ok) {
return ShopifyResponse::from(
$exchangeResult->log,
$exchangeResult->response,
);
}
ShopifyAccessToken::create([
"shop" => $exchangeResult->accessToken->shop,
"access_mode" => $exchangeResult->accessToken->accessMode,
"token" => $exchangeResult->accessToken->token,
"scope" => $exchangeResult->accessToken->scope,
"refresh_token" => $exchangeResult->accessToken->refreshToken,
"expires" => $exchangeResult->accessToken->expires,
"refresh_token_expires" =>
$exchangeResult->accessToken->refreshTokenExpires,
]);
}
$request->merge([
"shop" => $result->shop,
"shopifyHeaders" => $result->response->headers ?? [],
]);
$response = $next($request);
foreach ($request->input("shopifyHeaders", []) as $header => $value) {
$response->headers->set($header, $value);
}
return $response;
}
}
### Verbose output
Shopify\App\Types\ResultWithExchangeableIdToken {#288 ▼ // app/Http/Middleware/VerifyShopifyRequest.php:30
+ok: false
+shop: null
+idToken: null
+userId: null
+newIdTokenResponse: null
+log: Shopify\App\Types
\
LogWithReq {
#290 ▼
+code: "redirect_to_patch_id_token_page"
+detail: "Embedded app without id_token. Redirect to the patch ID token page to obtain a new token using the provided response."
+req: array:4 [▼
"method" => "GET"
"headers" => array:27 [▶]
"url" => "http://signatures-proceedings-neither-inspiration.trycloudflare.com/sales"
"body" => ""
]
}
+response: Shopify\App\Types
\
ResponseInfo {
#291 ▼
+status: 302
+body: ""
+headers: array:1 [▼
"Location" => "http://signatures-proceedings-neither-inspiration.trycloudflare.com/auth/patch-id-token?shopify-reload=%2Fsales"
]
}
}
### Operating system
NixOS
### CLI version
3.91.0
### Shell
bash
### Nodejs version
v22.22.0
### What language and version are you using in your application?
PHP 8.2