Showing social media previews for Laravel auth protected pages
Poking holes in protection for better looking links!
I've been working with a large internal-only website recently where almost all pages are locked behind Laravel's authentication system, meaning any links to the site redirect to the login page.
This is ideal, except during lockdown, the company has heavily moved to using Microsoft Teams for more internal messages, which shows a lovely social-media style preview for all links.
(the preview from sharing this blog on teams)
But when pages redirect to a login, you get login text or nothing is unhelpful and boring. Let's change that, so product links can have some custom descriptions picked up by teams even through the login page!
First we head to app\Http\Middleware\Authenticate.php
which is where laravel finds out where to redirect users. I want to add some info about products if people link to a product page so added the following:
protected function redirectTo($request)
{
if ($request->is('product/sku/**')) {
return route('login', ['sku' => $request->sku]);
}
if (! $request->expectsJson()) {
return route('login');
}
}
That finds any request for a /product/sku/{sku} page and adds the sku to the login as an additional query. You could add a service class here to give a more dedicated home to this, but as I only want to deal with products I'll stick with this for now.
Next we add some logic to use that query field in the login controller:
//app\Http\Controllers\Auth\LoginController.php
//[...]
public function showLoginForm(Request $request)
{
$product = null;
if ($request->has('sku')) {
$product = Product::setEagerLoads([])
->select('sku','description', 'status', 'image_url')
->find($request->sku);
}
return view('auth.login', [
'product' => $product
]);
}
Note the use of 'select' to grab specific fields and setEagerLoads()
to avoid eager loading default model relationships. We don't need much info here, so lets only get what's needed.
Now in your login view you can add some custom metadata when product exists, or display custom text depending on where the user will be redirected on login.
//resources\views\auth\login.blade.php
//[...]
@if($product)
<x-social-meta
title="{{$product->sku}} - {{$product->status}}"
description="{{$product->description}}"
image="{{$product->image_url}}"
url="{{$product->url}}"
/>
@endif
(this uses a social-meta component like the one in Blade UI kit)
And with that we're done! Links now show a basic product info preview in teams, but still force users to log in to see the same.
Notes
- This does expose data outside the authenticated system - don't put anything you need to keep private into the login page!
- If you have various data or models you want to show based on different paths, you'll want to build a class to return a
$meta
object to pass through to the view, rather than getting and passing your model directly and having to duplicate work in the view. - For testing use
$this->followingRedirects()->get($product->url)->assert...
to get to the login page with you extra info set, so you can assert it exists etc.