A tutorial to demonstrate how to add authorization to a Laravel API with Magic's Laravel Plugin.
Prerequisites
Quickstart: https://magic.link/posts/magic-laravel
This guide covers building an API protected by Magic issued DID token. This type of API is typically consumed by Mobile, Desktop and Native applications using Magic’s Web, React Native, iOS or Android Client SDK.
This guide demonstrates:
- How to check for a Decentralised ID Token (DIDT) in the
Authorization
header of an incoming HTTP request. - How to check if the token is valid, using the validate() of Magic’s Laravel SDK
This guide assumes:
- You have already configured your client-side app with the Magic Client SDK
Your Laravel Application is up and running, if not, please run the following command to get it started.
This guide assumes:You have already configured your client-side app with the Magic Client SDK
-
Your Laravel Application is up and running, if not, please run the following command to get it started.
Via Composer
composer create-project laravel/laravel magic-app cd magic-app php artisan serve
Via Laravel Installer
Or, you may install the Laravel Installer as a global Composer dependency:
composer global require laravel/installer laravel new magic-app cd magic-app php artisan serve
Validate DID Tokens
Install dependencies
Protecting your Laravel API requires a middleware which will check for and verify a bearer token in the Authorization header of an incoming HTTP request. We'll do that using tools provided by the Magic Laravel SDK.
composer require magiclabs/magic-laravel
Configure the plugin
The magic-laravel
plugin comes with a configuration file that can be generated using Artisan. First, generate the configuration file from the command line:
php artisan vendor:publish --provider="MagicLaravel\ServiceProvider"
After the file is generated, it will be located at config/magic.php
.
// config/magic.php
return [
/*
|--------------------------------------------------------------------------
| Secret API Key
|--------------------------------------------------------------------------
|
| Your API secret key retrieved from https://dashboard.magic.link
|
*/
'secret_api_key' => env('MAGIC_SECRET_API_KEY', null),
/*
|--------------------------------------------------------------------------
| HTTP request strategy
|--------------------------------------------------------------------------
|
| Customize your HTTP request strategy when making calls to the Magic API
|
*/
'http' => [
'retries' => env('MAGIC_RETRIES', 3), // Total number of retries to allow
'timeout' => env('MAGIC_TIMEOUT', 10), // A period of time the request is going to wait for a response
'backoff_factor' => env('MAGIC_BACKOFF_FACTOR', 0.02), // A backoff factor to apply between retry attempts
],
];
Get your Magic Secret Key
Sign Up with Magic and get your MAGIC_SECRET_KEY
.
Feel free to use the Test Application automatically configured for you, or create a new one from your Dashboard.
For added security, in Magic's dashboard settings (https://dashboard.magic.link), you can specify the URLs that are allowed to use your live API keys. Test API keys are always allowed to be used on localhost, however, it will block your Live API keys from working anywhere except the URLs specifically added to your allow list.
Edit the .env
file to add the configuration values needed to verify the incoming DID tokens.
MAGIC_SECRET_API_KEY=sk_test_123456789
MAGIC_RETRIES=
MAGIC_TIMEOUT=
MAGIC_BACKOFF_FACTOR=
Protect API Endpoints
The routes shown below are available for the following requests:
-
GET /api/public
: available for non-authenticated requests -
GET /api/private
: available for authenticated requests containing a DID Token
For the private
API route, we'll need a middleware to check for a bearer token in an Authorization
header for the request and then verify that the token is valid. We'll create that middleware using the make:middleware
Artisan command:
php artisan make:middleware CheckDIDT
Now, let's implement the handle()
method that Laravel will call automatically for the route:
<?php
// App/Http/Middleware/CheckDIDT.php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Magic;
use MagicAdmin\Exception\DIDTokenException;
use MagicAdmin\Exception\RequestException;
class CheckDIDT
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
$did_token = $request->bearerToken();
if($did_token){
try {
//verifying the DID Token
Magic::token()->validate($did_token);
$user = Magic::user()->get_metadata_by_token($did_token);
if (!$user) {
return response()->json(["message" => "Unauthorized user"], 401);
}
} catch (DIDTokenException $e) {
return response()->json(["message" => $e->getMessage()], 401);
} catch (RequestException $e) {
return response()->json(["message" => "Request Exception"], 401);
}
} else {
return response()->json(["message" => "Bearer token missing"], 401);
}
return $next($request);
}
}
This middleware:
- Retrieves the Bearer token from the request, and calls the
validate
function with it to verify the DIDT. - Uses the DID Token to retrieve User’s Meta Data
Magic::user()->get_metadata_by_token($did_token)
- Catches any exceptions thrown if the DIDT is expired, malformed or invalid. Also, checks for
RequestException
.
Next, we register this middleware in the HTTP Kernel with the name didt
:
// App/Http/Kernel.php
// …
class Kernel extends HttpKernel {
// ...
protected $routeMiddleware = [
// ...
'didt' => \App\Http\Middleware\CheckDIDT::class,
// …
}
We are now able to protect individual API endpoints by applying the didt
middleware:
// routes/api.php
// This endpoint does not need authentication.
Route::get('/public', function (Request $request) {
return response()->json(["message" => "Hello from a public endpoint! You don't need to be authenticated to see this."]);
});
// These endpoints require a valid did token and fetches user's data using did token
Route::get('/private', function (Request $request) {
return response()->json([
"message" => "Hello from a private endpoint! You need to have a valid DID Token to see this.",
"user" => Magic::user()->get_metadata_by_token($request->bearerToken())->data
]);
})->middleware('didt');
The /api/private
route is now only accessible if a valid DID Token is included in the Authorization
header of the incoming request.
Obtaining DID Token
Fork the template code on Codesandbox
To get the DID Token for testing, use our Laravel API Authorization template in CodeSandBox.
Update the MAGIC_PUBLISHABLE_KEY
Replace the pk_test_5A2E52658C87281B
string with your Publishable API Key
from the Magic Dashboard: on line 46
/* 2️⃣ Initialize Magic Instance */
const magic = new Magic("pk_test_5A2E52658C87281B");
Live Frontend Application 🎉
You have a working Frontend Application.
Login and copy the DID Token
for Testing the API with Postman.
Using your API
The /api/private
route is now only accessible if a valid DID Token is included in the Authorization
header of the incoming request.
Now, let’s start the Laravel server locally:
php artisan serve --port=8001
Send a GET
request to the public route - http://localhost:8001/api/public
- and you should receive back:
{
"message": "Hello from a public endpoint! You don't need to be authenticated to see this."
}
Now send a GET
request to the private route - http://localhost:8001/api/private
- and you should get a 401 status and the following message:
{ "message": "Bearer token missing" }
Add an Authorization
header set to Bearer DID_TOKEN
using the token generated above. Send the GET
request to the private route again and you should see:
{
"message": "Hello from a private endpoint! You need to have a valid DID Token to see this.",
"user": {
"email": "your_email@provide.com",
"issuer": "did:ethr:0xaa12b334C1f3d……….62367e5B8e",
"public_address": "0xaa12b334C1f3d……….62367e5B8e"
}
}
Done 🎉
Congratulations! You have successfully secured your Laravel API with Magic.
Top comments (0)