Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

kenprogrammer's avatar

Building API Key Generator

I want to build an API Key generator. Here are some of the code snippets:

API keys table

 /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('api_keys', function (Blueprint $table) {
            $table->id();
            $table->string('token');
            $table->datetime('expires_at');
            $table->timestamps();
        });
    }

API Key Generation logic. Bear in mind that this would be full CRUD with option to revoke etc. NOTE : This is just an example. This key can only be generated by logged in users:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Str;
use App\Models\ApiKey;

class ApiKeyController extends Controller
{
    public function generateApiKey()
    {
        $apiKey=(string) Str::orderedUuid();

        $query=ApiKey::create([
            "token"=>$apiKey,
            "expires_at"=>now()->addMinutes(30)
        ]);

       dd($apiKey);
    }
}

API Key authentication Middleware:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
use App\Models\ApiKey;
use Carbon\Carbon;

class AuthenticateApiKey
{
    /**
     * Handle an incoming request.
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next): Response
    {
        $token = $request->bearerToken(); // Get the Bearer Token from the request

        if (!$token) {
            return response()->json(['message' => 'Unauthorized'], 401);
        }

        $apiKey = ApiKey::where('token', $token)->first();

        if (!$apiKey) {
            return response()->json(['message' => 'Invalid API key'], 401);
        }

        // Check if the API key has expired
        if ($apiKey->expires_at && Carbon::now()->gt($apiKey->expires_at)) {
            return response()->json(['message' => 'API key has expired'], 401);
        }

        return $next($request);
    }
}

Middleware Alias:

'api.key' => \App\Http\Middleware\AuthenticateApiKey::class,

Usage:

Route::middleware('api.key')->group(function () {
    Route::get('/test-api', function () {
        return response()->json(['message' => 'Access Granted!']);
    });
});

Am I missing anything or is there an OAuth2 flow that I can use to produce similar results?

NB: This is for use in authenticating public APIs or APIs that DO NOT require user authentication such as those for SPA blog apps or you want to give third-party apps an option to access some resources of your application.

0 likes
9 replies
martinbean's avatar

@kenprogrammer I don’t really understand what you’re trying to do? You have a route, that returns an API key, that you then use to authorise API requests? Well what’s to stop someone just hitting that route themselves and getting API keys?  

kenprogrammer's avatar

@martinbean This is just an example. API Keys will be created by logged in users. Updating the question to clarify.

wafto's avatar

Well In such cases is better to use Laravel sanctum, but if not I will said that you are missing the guard part so you can access the auth user anywhere your app, also you should add the relationship user has many apikeys.

Other thing is to create a command to flush the expired keys.

So many things that in the end packages can deal it better. the best way to learn is to dive into the GitHub repo from packages that does the same like Laravel sanctum.

kenprogrammer's avatar

@wafto API Keys will not require user authentication. This is like WordPress API Key when you want to use it as an Headless CMS. Sanctum will be used to manage system users. Users will login to into the system and generate API Keys. which they can use in other apps to access the some resources in our subject system.

wafto's avatar

@kenprogrammer Ok, maybe only flushing the expired ones and continue with your initial idea.

1 like
martinbean's avatar

@kenprogrammer An API key has nothing to do with a CSS library like Tailwind. Besides, the very first sentence on that page reads:

Jetstream includes first-party integration with Laravel Sanctum.

kenprogrammer's avatar

@martinbean Am referring to API management that's if you use Jetstream as starter kit since you can enable more options as needed.

Please or to participate in this conversation.