A Shopify App in Laravel Pt 3 - The User Model
In the last article we made it to the installation page of your app. In this article we are going to:
- Create the User model: Each site (eg promeate.myshopify.com) will be a “User”
- Setup auth route scaffolding: Create the basic auth route and plan its logic
- Implement install request verification: Validate that the install confirmation actually came from Shopify (ie protect our app)
- Create a new User and redirect to the App dashboard: Finally, once install request has been verified for a new site, we create a new user and redirect them to the App dashboard.
Create user model
Rather than create a user model from scratch we are going to slightly modify the default Laravel User model here - jump into users table migration (found in database > migrations, with create_users table in name), and change the users table schema to the following:
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('site')->unique();
$table->string('access_token');
$table->rememberToken();
$table->timestamps();
});
Finally, ensure you have a database configured, then run php artisan migrate
to create the tables.
In short:
- we wanted site (eg promeate.myshopify.com) to be the unique field, not an email address - an email address would be useful as well, but we’ll keep things simple for now)
- We need to store the access token with the site name in order to access the site from the app.
- If you want to dot I’s and cross t’s, you can jump in and update the user model itself (User.php) to reflect these changes.
Setup auth route scaffolding
You might recall in the previous article, when we were redirecting to the dashboard install page we included a parameter called “redirect_uri” - we set this up to be /auth for our app, so this is what we will configure now.
- Open web.php and add the auth route
Route::get('/auth', 'AppController@auth');
- Open your controller (AppController.php), and create the auth method. While I’m here’s I will scaffold out the logic that will will be implementing…
public function auth(Request $request)
{
return 'Welcome to the auth route';
// if (Shopify request is ok)
// if (this is new store)
// request access token, create a new user account
// Log user in to the store, redirect their dashboard
// else (abort)
}
Now when you click install you should see “Welcome to the auth route”.
Implement request verification
Rather than try to explain how our app is going to verify the auth request is actually coming from Shopify, I will simply quote the Shopify documentation:
First, the hmac parameter is removed from the hash. Next, the remaining keys in the hash are sorted lexicographically, and each key and value pair is joined with an ampersand (‘&’). The resulting string is hashed with the SHA256 algorithm using the application’s secret key as the encryption key. The resulting digest is compared against the hmac parameter provided in the request. If the comparison is successful, you can be assured that this is a legitimate request from Shopify.
Their example was in Ruby, but there’s a PHP one over here that I shamelessly copied below with minimal changes (all credit to Alex Markov).
public function auth(Request $request)
{
$shared_secret = env('SHARED_SECRET');
$params = $_GET;
$hmac = $request->hmac;
$shop_name = $request->shop;
$params = array_diff_key($params, array('hmac' => ''));
ksort($params);
$computed_hmac = hash_hmac('sha256', http_build_query($params), $shared_secret);
// Validate Shopify's request
if (hash_equals($hmac, $computed_hmac)) {
return "Yep the request was legitimate";
// if (this is new store)
// request access token, create a new user account
// Log user in to the store, redirect their dashboard
} else {
abort(401, 'Unauthorized action.');
}
}
Try clicking GET to ensure this is working.
Create a new user and and redirect to the App Dashboard
First, we need to create a dashboard page that we can redirect to:
- In web.php add
Route::get('/dashboard', 'AppController@dashboard')->middleware('auth');
- note this is the first route that requires you to be logged in, hence applying the auth middleware. - Create the dashboard method in AppController.php
public function dashboard(Request $request)
{
$user = Auth::user();
return "Welcome to your dashboard ".$user->site;
}
Finally, we can jump back in the auth method and fill out the missing logic. First we need to add 2 use statements to the header
use App\User;
use Illuminate\Support\Facades\Auth;
Then finally we can complete the auth method as show below, adding this missing logic.
public function auth(Request $request)
{
$shared_secret = env('SHARED_SECRET');
$params = $_GET;
$shop_name = $request->shop;
$hmac = $request->hmac;
$code = $request->code;
$params = array_diff_key($params, array('hmac' => ''));
ksort($params);
$computed_hmac = hash_hmac('sha256', http_build_query($params), $shared_secret);
// Valicate Shopify's request
if (hash_equals($hmac, $computed_hmac)) {
if (! User::where('site', '=', $shop_name)->exists()) {
// Create a new user account
$new_user = new User;
$new_user->site = $shop_name;
$new_user->access_token = $access_token;
$new_user->save();
}
// Get current user, login and redirect to dashboard
$user = User::where('site', '=', $shop_name)->firstOrFail();
Auth::login($user);
return redirect()->action('AppController@dashboard');
} else {
abort(401, 'Unauthorized action.');
}
}