Kyon147 / laravel-shopify

A full-featured Laravel package for aiding in Shopify App development
MIT License
353 stars 102 forks source link

New Scopes added to an existing app but Shopify not updating the app #186

Closed ecomzier closed 1 year ago

ecomzier commented 1 year ago

Hi,

I added new Scopes to an existing app but Shopify does not update the app and not showing any prompt to update the app when we open the app from Shopify store admin.

Even we have tried it from different stores and no prompt appeared from Shopify to approve the new scopes. As we are running and building apps for the last 4 years and never saw this behavior before.

I also removed the token from DB and then open the app from the Shopify store and the app does not reauthenticated and does not ask to approve anything.

usmanpakistan commented 1 year ago

@ecomzier I have faced a similar issue. You have to manually redirect the app to authenticate page to force the user to approve the new scope. so I created a middleware to check for scopes and reauthenticate the app if scopes are missing. Here is the Middleware code.

routes/web.php

Route::middleware(['verify.shopify', 'billable', EnsureScopesAreUpToDate::Class])->group(function ()
{
    Route::get('/', [HomeController::class, 'index'])->name('home');
});

app/Http/Middleware/EnsureScopesAreUpToDate.php

class EnsureScopesAreUpToDate
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse)  $next
     * @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
     */
    public function handle(Request $request, Closure $next)
    {
        $user        = User::where('name', $request->get('shop'))->first();
        $scopes_resp = $user->api()->rest('GET', '/admin/oauth/access_scopes.json');

        if ($scopes_resp["errors"]) {
            \Log::debug("Error in fetching scope");
            return $next($request);
        }

        $scopes = json_decode(json_encode($scopes_resp["body"]["access_scopes"]));
        $scopes = array_map(function ($scope)
        {
            return $scope->handle;
        }, $scopes);

        $requiredScopes = explode(',', env('SHOPIFY_API_SCOPES'));

        $missingScopes = array_diff($requiredScopes, $scopes);
        if (count($missingScopes) == 0) {
            \Log::debug("Scopes Verified");
            return $next($request);
        }

        \Log::debug("Scope missing. Reauthenticate the App");
       $authRoute = Util::getShopifyConfig('route_names.authenticate');
        return redirect()->route($authRoute , ['shop' => $user->name,  'host' => $request->get('host') ]  );
    }
}

Discussion at #88 led to this solution

usmanpakistan commented 1 year ago

@Kyon147 I see a few people having similar issues while updating scopes. Should I add a PR and add this middleware to the package?

Kyon147 commented 1 year ago

@usmanpakistan yeah defo, if this is something other people are experiencing. The package should do this automatically, but something have obviously changed and needs to be updated.

RishabhTayal commented 1 year ago

Looking forward to get this fixed.

Kyon147 commented 1 year ago

This is how Shopify's ruby app handles it https://github.com/Shopify/shopify_app/blob/main/lib/shopify_app/access_scopes/user_strategy.rb#L7

Checks to see if it has either no scope i.e a clean install or gets the scopes from a shop using the app call and compares if they are the same or not as set in the config.

It looks pretty much the same way you are doing it @usmanpakistan.

The one thing we'd want to do is make this a named middleware, so it can be added like the verify.shopify or billable classes. Something like verify.scopes so we have consistent naming.

usmanpakistan commented 1 year ago

@Kyon147 PR created

Kyon147 commented 1 year ago

PR #187 is nearly there, I just need to tweak some of the tests at the weekend and it should go out next week hopefully