<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Delaney S.</title>
    <description>The latest articles on DEV Community by Delaney S. (@delaneys).</description>
    <link>https://dev.to/delaneys</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F288976%2Fe19530bd-7d96-4bb5-b1b6-b159d7f7d145.jpg</url>
      <title>DEV Community: Delaney S.</title>
      <link>https://dev.to/delaneys</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/delaneys"/>
    <language>en</language>
    <item>
      <title>The Ultimate Fantasy Premier League Hack: AI-Generated Transfers Using Amazon Bedrock and RAG Agents</title>
      <dc:creator>Delaney S.</dc:creator>
      <pubDate>Sun, 06 Apr 2025 17:06:30 +0000</pubDate>
      <link>https://dev.to/delaneys/building-an-fpl-transfer-rag-agent-using-amazon-bedrock-3k05</link>
      <guid>https://dev.to/delaneys/building-an-fpl-transfer-rag-agent-using-amazon-bedrock-3k05</guid>
      <description>&lt;p&gt;Last weekend, while attending an AWS West Africa Meetup on "AI-Powered Innovation", I heard about Amazon Bedrock for the first time in a way that piqued my interest. Amazon Bedrock is a "fully managed service that offers a choice of high-performing foundation models (FMs) from leading AI companies". In simpler terms, it allows you build generative AI applications, with easy access to FMs like ChatGPT and Claude via an API.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fucylurr15mj3xufr0hji.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fucylurr15mj3xufr0hji.png" alt="Amazon Bedrock" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I immediately knew I had to try it out, and I decided to build a Retrieval Augmented Generation (RAG) agent to recommend Fantasy Premier League (FPL) transfers. FPL is a game of strategy, data, and smart decision-making. Deciding which players to transfer in and out of their team each week is basically the biggest challenge for FPL managers.&lt;/p&gt;

&lt;p&gt;Here's the &lt;a href="https://github.com/Delaney/fpl-transfer-advisor" rel="noopener noreferrer"&gt;repo&lt;/a&gt;, where I plan to keep evolving the agent, and a &lt;a href="https://fpl-transfer-advisor-fe.vercel.app" rel="noopener noreferrer"&gt;live demo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A RAG agent is simply an AI agent with retrieval capability, allowing it to have access to current and accurate data. In this example, I'll build an agent with access to the latest FPL rules and selection guidelines. For now, the recommendation options would be given to it manually in the prompt.&lt;/p&gt;

&lt;p&gt;You will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set up a rules knowledge base for your agent&lt;/li&gt;
&lt;li&gt;Store player data and query it for recommendations&lt;/li&gt;
&lt;li&gt;Get your agent to recommend the best possible transfers&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Setting Up
&lt;/h2&gt;

&lt;p&gt;After setting up your project (in this example, I am using &lt;strong&gt;TypeScript&lt;/strong&gt; &amp;amp; &lt;strong&gt;Express.js&lt;/strong&gt;), you can go ahead and set up the necessary AWS infrastructure. These are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Amazon Bedrock: for accessing FMs and building agents&lt;/li&gt;
&lt;li&gt;S3: for storing knowledge base resources. There are other options, such as Confluence pages and crawled web pages.&lt;/li&gt;
&lt;li&gt;DynamoDB (specific to this option): for easy storage and retrieval of player data&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  DynamoDB
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Create a DynamoDB table &lt;code&gt;FPLPlayers&lt;/code&gt; with a primary key of &lt;code&gt;playerId&lt;/code&gt;. Then, add a global secondary index (GSI) with a partition key of &lt;code&gt;position&lt;/code&gt; and a sort key of &lt;code&gt;form&lt;/code&gt;. This would allow you to easily query players in top form.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Amazon Bedrock
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Request access to an Amazon Bedrock LLM. For this, I chose Claude 3 Sonnet, but you will have access to almost 50 others.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq4lsyzgi9pixosjv6008.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq4lsyzgi9pixosjv6008.png" alt="LLM Selection" width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Once the model is available, it's time to set up your knowledge base. Create an S3 bucket and upload your documents there. For me, this was a PDF containing the rules for FPL transfers and team selections. When that is done, from the AWS Bedrock console, create a new Knowledge Base and select the path to the S3 bucket in the settings.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next, select the embeddings model and the vector store. I used Titan Text Embeddings v2 and Amazon OpenSearch Serverless Vector Store, respectively, as they are great options.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting Data
&lt;/h2&gt;

&lt;p&gt;We can set up some methods for our FPL data. First, we need to add some types.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export interface Main {
    elements: Player[];
}

export interface Player {
    id: number;
    web_name: string;
    element_type: number;
    team: number;
    now_cost: number;
    total_points: number;
    selected_by_percent: string;
    form: string;
    status: string;
    expected_goals_conceded: string;
    minutes: number;
    team_code: number;
    chance_of_playing_next_round: number;
}

export interface FPLTeam {
    picks: {
        element: number,
        element_type: number;
        name?: string;
    }[];
    transfers: {
        bank: number;
        limit: number;
    };
}

export interface TransferSuggestion {
    out: string;
    in: string;
    cost: number;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we store players on DynamoDB. I added the next fixture difficulty using data from the FPL API. I also added a job to call this endpoint daily, making sure the data is up-to-date:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzzht37tw0qeh53ogyvon.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzzht37tw0qeh53ogyvon.png" alt="Method to store player data on DynamoDB" width="800" height="772"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And retrieve them for recommendation options:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6mr9v945rptneti1vwzu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6mr9v945rptneti1vwzu.png" alt="Method to store recommended player data from DynamoDB" width="800" height="1389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As the project evolves, we can store more statistics to enable the agent to make better decisions. But for now, we'll rely on the player's form, price, and the difficulty of the next fixture.&lt;/p&gt;

&lt;p&gt;Let's set up our agent to make decisions using the Knowledge Base. On the AWS console, create a new agent. Select your Foundational Model, &lt;br&gt;
and enter precise instructions for your agent to follow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fotb31qi2dwn3wqs2c9g6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fotb31qi2dwn3wqs2c9g6.png" alt="Image description" width="800" height="655"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, create an Action Group. After you create the agent, you can assign a Knowledge Base and prepare the agent. After that, you can create an Alias for your agent. Note down your Agent ID and the Alias ID.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz4bbylnrk65w0ojveihp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz4bbylnrk65w0ojveihp.png" alt="Agent Details" width="800" height="516"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmbzqxva7k2xdb20731mj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmbzqxva7k2xdb20731mj.png" alt="Alias Details" width="800" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, we can call our agent. First, I get the user's team data (players, free transfers left, and budget) and top recommendation (players with a form equal to or greater than a set value). With those, I can create a prompt, which is then sent to my agent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {
    BedrockAgentRuntimeClient,
    InvokeAgentCommand,
} from "@aws-sdk/client-bedrock-agent-runtime";
import config from './config';
import {getRecommendationData} from "./dynamo";

const client = new BedrockAgentRuntimeClient({
    region: config.awsRegion,
    credentials: {
        accessKeyId: config.awsAccessKey,
        secretAccessKey: config.awsSecretKey,
    }
});

const agentId = config.awsAgentId;
const agentAliasId = config.awsAgentAliasId;

export async function invokeBedrock(modelId: string, prompt: string) {
    const sessionId = Math.random().toString(36).substring(2);
    const command = new InvokeAgentCommand({
        agentId,
        agentAliasId,
        sessionId,
        inputText: prompt,
        streamingConfigurations: {
            streamFinalResponse: true,
        },
    });

    let recommendations = "";
    const response = await client.send(command);

    if (response.completion === undefined) {
        throw new Error("Completion is undefined");
    }

    for await (const chunkEvent of response.completion!) {
        const chunk = chunkEvent.chunk!;
        const decodedResponse = new TextDecoder("utf-8").decode(chunk.bytes);
        recommendations += decodedResponse;
    }

    return recommendations;
}

/**
 * API function to get FPL advice.
 */
export async function getFPLAdvice(teamId: number, cookie: string): Promise&amp;lt;string&amp;gt; {
    const {userPlayers, recommendations, freeTransfers, budget} = await getRecommendationData(teamId, cookie);

    const prompt = `
  The user’s current team is:\n
  ${userPlayers.map((p) =&amp;gt; `- ${p.name} (Position: ${p.position}, Team: ${p.team}) (Form: ${p.form}, Price: £${p.price}, Next Fixture Difficulty: ${p.nextFixtureDifficulty})`).join(`\n`)}.\n

 The user has only ${freeTransfers} free transfers left, and a budget of ${budget}.

 Based on the current gameweek, the best transfer options are:\n
  ${recommendations.map((p) =&amp;gt; `- ${p.name} (Position: ${p.position}, Team: ${p.team}) (Form: ${p.form}, Price: £${p.price}, Next Fixture Difficulty: ${p.nextFixtureDifficulty})`).join(`\n`)}.

 Return nothing else but the recommendations in a readable format, clearly showing the player going out and the player coming in for each suggested transfer. For example:

 Out: [Player Name from Current Team]
 In: [Player Name from Best Transfer Options]
 Cost: [Cost to make transfer, should be negative if out &amp;gt; in]
  `;

    return await invokeBedrock(
        "anthropic.claude-3-sonnet-20240229-v1:0",
        prompt
    );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it! We can connect this function to an endpoint; calling it should give us some recommendations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffmwxb32o3idszos01sa8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffmwxb32o3idszos01sa8.png" alt="Image description" width="800" height="173"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But there's always room for improvement. We can add more to our Knowledge Base or even build more agents to handle other tasks, allowing multi-agent orchestration.&lt;/p&gt;

&lt;p&gt;As you can see, the ability to build agents without almost no code and the value they can deliver makes Amazon Bedrock a powerful tool for utilising AI modes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I hope you found this helpful and that you start building powerful RAG agents to supercharge your ideas. Happy coding!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>aws</category>
      <category>awsbedrock</category>
      <category>typescript</category>
    </item>
    <item>
      <title>HMAC Authentication in Laravel</title>
      <dc:creator>Delaney S.</dc:creator>
      <pubDate>Sat, 05 Aug 2023 18:53:49 +0000</pubDate>
      <link>https://dev.to/delaneys/hmac-authentication-in-laravel-4je9</link>
      <guid>https://dev.to/delaneys/hmac-authentication-in-laravel-4je9</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7eone13lvx2fl13sxxug.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7eone13lvx2fl13sxxug.jpg" alt="Security, Security, Security!" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While working on a set of API webhooks recently, I needed to provide some security scheme that allowed the client to verify that the webhook request was being sent by the correct server, which I was working on. After a little online research, I came across the HMAC scheme for API requests. After a little explanation, I will give an example of implementing this for API endpoints in Laravel.&lt;/p&gt;

&lt;p&gt;Hash-based Message Authentication Code (HMAC) is a code obtained using a cryptographic hash function, data and a secret. It’s used to verify the authenticity of the source and content of a request. Both the client and server share a pre-known secret key for generating HMACs.&lt;/p&gt;

&lt;p&gt;In simpler terms, there is a secret key that is shared by and known to only the server and client. A hash function uses this key to generate a code whenever a request is made. This code is then added to the request and sent. When the receiving app gets the request, it runs the same process used to create the code, using the details from the request it just received and the secret key it has stored. If the sender is really who they’re meant to be, both the code in the request and the code that has just been generated should match, and the receiver can continue processing the request. Pretty clean, right?&lt;/p&gt;

&lt;p&gt;It’s a simple yet effective authentication method, as the integrity checks do not allow for man-in-the-middle attacks unless they possess the secret key. However, a bad guy could resend the same request over and over, and that could cause damage to data or reveal some sensitive information. These are called Replay Attacks, and there are a number of ways to deal with those, but I won’t be talking about any as I plan to keep this as simple as possible.&lt;/p&gt;

&lt;p&gt;Now for a quick explanation of our hash function. The values we would be using are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;URL&lt;/strong&gt;: The full URL in lowercase, including any query parameters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verb&lt;/strong&gt;: The HTTP method for the request in uppercase, e.g. POST.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content MD5&lt;/strong&gt;: An MD5 hash of the request body in JSON&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The steps we would take to create the hash code are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a signed string using our values above.&lt;/li&gt;
&lt;li&gt;Generate a hash using the string and our secret key.&lt;/li&gt;
&lt;li&gt;Base64 encode the hash and attach it to the request header&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Other values, such as the request content type, can be used, but I’ll keep it simple. Each API’s scheme for creating the signed string used for hashing is usually described in the API’s documentation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up
&lt;/h3&gt;

&lt;p&gt;To start, spin up a new Laravel application and add a couple of controllers to add our API logic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:controller UsersController
php artisan make:controller ClientController
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add a few routes for the endpoints in routes/api.php&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Route::prefix('/')-&amp;gt;middleware('auth.hmac')-&amp;gt;group(static function () {
    Route::get('/users', [App\Http\Controllers\UsersController::class, 'getAll']);
    Route::get('/users/{id}', [App\Http\Controllers\UsersController::class, 'getOne']);
    Route::post('/users', [App\Http\Controllers\UsersController::class, 'create']);
    Route::put('/users/{id}', [App\Http\Controllers\UsersController::class, 'update']);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I’ve assigned a middleware &lt;code&gt;auth.hmac&lt;/code&gt; to the routes, and I'll return to this later. Next, save the example public and secret keys in the &lt;code&gt;.env&lt;/code&gt; file and reference them in a config file &lt;code&gt;config/hmac.php&lt;/code&gt;. The public key here is the intended request header key for the HMAC.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# .env
HMAC_PUBLIC_KEY="X-MEN-SIGNATURE"
HMAC_SECRET_KEY="Xavier's School for Gifted Youngsters"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- hmac.php --&amp;gt;
&amp;lt;?php
    return [
        'public' =&amp;gt; 'X-MEN-SIGNATURE',
        'secret' =&amp;gt; "Xavier's School for Gifted Youngsters"
    ];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, a few methods in the controllers to create, get and edit users for the simple context of this tutorial. The User model comes with the Laravel install; we don’t need to change anything.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;

class UsersController extends Controller
{
    public function getAll(Request $request)
    {
        $users = User::all();
        return response()-&amp;gt;json($users);
    }

    public function getOne(Request $request, $id)
    {
        $user = User::findOrFail($id);
        return response()-&amp;gt;json($user);
    }

    public function create(Request $request)
    {
        $validator = Validator::make($request-&amp;gt;all(), [
            'name' =&amp;gt; 'required',
            'email' =&amp;gt; 'required|email|unique:users',
            'password' =&amp;gt; 'required|min:6'
        ]);
        if ($validator-&amp;gt;fails()) {
            return response()-&amp;gt;json($validator-&amp;gt;errors()-&amp;gt;first(), 400);
        }
        extract($request-&amp;gt;all());
        $password = Hash::make($password);
        $user = User::create(compact('name', 'email', 'password'));
        return response()-&amp;gt;json($user);
    }
    public function update(Request $request, $id)
    {
        $user = User::findOrFail($id);
        $data = [
            'name' =&amp;gt; $request-&amp;gt;name ?? $user-&amp;gt;name,
            'email' =&amp;gt; $request-&amp;gt;email ?? $user-&amp;gt;email,
            'password' =&amp;gt; Hash::make($request-&amp;gt;name) ?? $user-&amp;gt;password
        ];
        $user-&amp;gt;update($data);
        return response()-&amp;gt;json($user);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Hash It Up
&lt;/h3&gt;

&lt;p&gt;Now, we have working controller logic for a simple API. However, making a call to it would result in an error due to the missing middleware. Let’s come back to that. This middleware is going to be the location for the HMAC authentication. Before the controller handles the request, we will confirm that it contains the correct HMAC header.&lt;/p&gt;

&lt;p&gt;Add a new middleware:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;php artisan make:middleware HmacAuth&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And register it by adding it to &lt;code&gt;$routeMiddleware&lt;/code&gt; in &lt;code&gt;App\Http\Kernel.php&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;protected $routeMiddleware = [
    ...
    'auth.hmac' =&amp;gt; \App\Http\Middleware\HmacAuth::class,
    ...
];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, for the real work. Remember the scheme used for creating the signed string. Let’s go ahead and implement it. First, we check if the header we need is even on the request and abort it if it isn’t.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$header = config('hmac.public');
$request_hash = $request-&amp;gt;headers-&amp;gt;get($header);
if (!$request_hash) {
    $message = 'Header `' . $header . '` missing.';
    abort('403', $message);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it is, we get our string, which is the concatenation using newlines, of the HTTP method, URL and the MD5 hash of the request body in JSON. Using the secret key, we then run the HMAC SHA-256 hashing algorithm on the string. This value is finally Base64 encoded using UTF8 and compared with the value in our HMAC header. If they match, we can keep processing the request, or else, we abort.&lt;/p&gt;

&lt;p&gt;Here’s what the final code should look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class HmacAuth
{
    /**
     * Handle an incoming request.
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next): Response
    {
        $header = config('hmac.public');
        $request_hash = $request-&amp;gt;headers-&amp;gt;get($header);
        if (!$request_hash) {
            $message = 'Header `' . $header . '` missing.';
            abort('403', $message);
        }

        $body = $request-&amp;gt;all();
        $url = config('hmac.webhook');
        $verb = $request-&amp;gt;method();
        $md5 = md5(json_encode($body));

        $string = $verb . PHP_EOL . $url . PHP_EOL . $md5;

        $hash = hash_hmac('SHA256', $string, config('hmac.secret'));
        $base64_hash = base64_encode($hash);

        if ($base64_hash !== $request_hash) {
            $message = 'Invalid `' . $header . '` Header';
            abort('403', $message);
        }

        return $next($request);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that’s all. HMAC signature verification is one of the simplest and most powerful methods for API requests and webhook authentication.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>api</category>
      <category>authentication</category>
    </item>
  </channel>
</rss>
