<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ authorization - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ authorization - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Thu, 14 May 2026 04:32:53 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/authorization/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Prevent IDOR Vulnerabilities in Next.js API Routes ]]>
                </title>
                <description>
                    <![CDATA[ Imagine this situation: A user logs in successfully to your application, but upon loading their dashboard, they see someone else’s data. Why does this happen? The authentication worked, the session is ]]>
                </description>
                <link>https://www.freecodecamp.org/news/prevent-idor-in-nextjs/</link>
                <guid isPermaLink="false">69a1f073d4053a09f3430559</guid>
                
                    <category>
                        <![CDATA[ Next.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ authorization ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ayodele Aransiola ]]>
                </dc:creator>
                <pubDate>Fri, 27 Feb 2026 19:28:51 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5fc16e412cae9c5b190b6cdd/b14a67ea-e78b-4ebd-996f-98da3a0a8027.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Imagine this situation: A user logs in successfully to your application, but upon loading their dashboard, they see someone else’s data.</p>
<p>Why does this happen? The authentication worked, the session is valid, the user is authenticated, but the authorization failed.</p>
<p>This specific issue is called <strong>IDOR (Insecure Direct Object Reference)</strong>. It’s one of the most common security bugs and is categorized under <strong>Broken Object Level Authorization (BOLA)</strong> in the OWASP API Security Top 10.</p>
<p>In this tutorial, you’ll learn:</p>
<ul>
<li><p>Why IDOR happens</p>
</li>
<li><p>Why authentication alone is not enough</p>
</li>
<li><p>How object-level authorization works</p>
</li>
<li><p>How to fix IDOR properly in Next.js API routes</p>
</li>
<li><p>How to design safer APIs from the start</p>
</li>
</ul>
<h2 id="heading-table-of-content">Table of Content</h2>
<ul>
<li><p><a href="#heading-table-of-content">Table of Content</a></p>
</li>
<li><p><a href="#heading-authentication-vs-authorization">Authentication vs. Authorization</a></p>
</li>
<li><p><a href="#heading-what-is-an-idor-vulnerability">What is an IDOR Vulnerability?</a></p>
</li>
<li><p><a href="#heading-the-vulnerable-pattern-in-nextjs">The Vulnerable Pattern in Next.js</a></p>
</li>
<li><p><a href="#heading-how-to-handle-idor-in-nextjs">How to Handle IDOR in Next.js</a></p>
<ul>
<li><a href="#heading-object-level-authorization">Object-Level Authorization</a></li>
</ul>
</li>
<li><p><a href="#heading-how-to-design-safer-endpoints-apime">How to Design Safer Endpoints (/api/me)</a></p>
</li>
<li><p><a href="#heading-mental-model-for-api-design">Mental Model for API Design</a></p>
</li>
<li><p><a href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-authentication-vs-authorization">Authentication vs. Authorization</h2>
<p>Before writing further, let’s clarify something critical.</p>
<ul>
<li><p><strong>Authentication answers:</strong> Who are you?</p>
</li>
<li><p><strong>Authorization answers:</strong> What are you allowed to access?</p>
</li>
</ul>
<p>In IDOR scenarios, authentication works (the user is logged in), while authorization is missing or incomplete. That distinction is the core lesson of this article.</p>
<h2 id="heading-what-is-an-idor-vulnerability">What is an IDOR Vulnerability?</h2>
<p>An IDOR vulnerability happens when your API fetches a resource by an identifier (like a user ID), and then you do not verify that the requester owns or is allowed to access that resource.</p>
<p>Example of such a request:</p>
<pre><code class="language-plaintext">GET /api/users/123
</code></pre>
<p>The code above is an HTTP <strong>GET</strong> request to the <code>/api/users/123</code> route. The <code>GET</code> method is used to request data from the server. This indicates that the client is requesting a specific user with the ID <code>123</code> and this request returns the user data in a response (often in JSON format).</p>
<p>If your backend makes the request using a similar structure to the code snippet below without checking who is making the request, you have an IDOR vulnerability, even if the user is logged in.</p>
<pre><code class="language-tsx">db.user.findUnique({ where: { id: "123" } })
</code></pre>
<p>What the code does is to query the database for a single user record. The <code>db.user</code> part refers to the <code>user</code> model/table and <code>findUnique()</code> is a method that returns only one record based on a unique field. Inside the method, the <code>where</code> clause specifies the filter condition and <code>{ id: "123" }</code> tells the database to find the user whose unique <code>id</code> equals <code>"123"</code>. If a matching record exists, it returns that user object; otherwise, it returns <code>null</code>.</p>
<h2 id="heading-the-vulnerable-pattern-in-nextjs">The Vulnerable Pattern in Next.js</h2>
<p>Looking at this Next.js App Router API route:</p>
<pre><code class="language-tsx">// app/api/users/[id]/route.ts
import { NextResponse } from "next/server";
import { db } from "@/lib/db";

export async function GET(
  req: Request,
  { params }: { params: { id: string } }
) {
  const user = await db.user.findUnique({
    where: { id: params.id },
    select: { id: true, email: true, name: true },
  });

  return NextResponse.json({ user });
}
</code></pre>
<p>Before going to the implication of this code snippet, let's understand what the code does. It defines a dynamic API route for <code>/api/users/[id]</code>. The exported <code>GET</code> function is an async route handler that runs when a GET request is made to this endpoint. It receives the request object and a <code>params</code> object, where <code>params.id</code> contains the dynamic <code>[id]</code> in the URL segment. The <code>db.user.findUnique()</code> method queries the database for a user whose <code>id</code> matches <code>params.id</code>, and the <code>select</code> option limits the returned fields to <code>id</code>, <code>email</code>, and <code>name</code>. Finally, <code>NextResponse.json()</code> sends the retrieved user data back to the client as a JSON response.</p>
<p>Now, to the implication, the code is a bad approach because the route accepts a user ID from the URL, fetches that user directly from the database, and returns the result. There is no session validation, no ownership check, and no role check.</p>
<p>If a logged-in user changes the <code>id</code> in the URL, they may access other users’ data. This is simply IDOR.</p>
<h2 id="heading-how-to-handle-idor-in-nextjs">How to Handle IDOR in Next.js</h2>
<p>The first element of defense is verifying identity. We’ll use <code>getServerSession</code> from NextAuth (adjust if using another auth provider). This change ensures that you read the session from the cookies, verify it on the server side, and ensure the user has a valid ID. This prevents unauthenticated access.</p>
<pre><code class="language-tsx">// lib/auth.ts
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/authOptions";

export async function requireSession() {
  const session = await getServerSession(authOptions);

  if (!session?.user?.id) {
    return null;
  }

  return session;
}
</code></pre>
<p>The code above defines an authentication helper function called <code>requireSession</code>. The <code>getServerSession(authOptions)</code> function retrieves the current user session on the server using the provided authentication configuration. The optional chaining (<code>session?.user?.id</code>) in the <code>if</code> block that follows safely checks whether a logged-in user and their <code>id</code> exist. If no valid session or user ID is found, the function returns <code>null</code>, indicating the request is unauthenticated. Otherwise, it returns the full <code>session</code> object so it can be used in protected routes or server logic.</p>
<p>You have successfully confirmed that the user and session exist; now, update the route:</p>
<pre><code class="language-tsx">export async function GET(
  req: Request,
  { params }: { params: { id: string } }
) {
  const session = await requireSession();

  if (!session) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  const user = await db.user.findUnique({
    where: { id: params.id },
    select: { id: true, email: true, name: true },
  });

  return NextResponse.json({ user });
}
</code></pre>
<p>The fix is incomplete yet, but in the above code, you’ve prevented anonymous access. The <code>GET</code> handler calls the <code>requireSession()</code> that was created earlier to verify that the request is authenticated. If no valid session is returned, it immediately responds with a JSON error message and a <code>401 Unauthorized</code> HTTP status. If the user is authenticated, it proceeds to call <code>db.user.findUnique()</code> to fetch the user whose <code>id</code> matches <code>params.id</code>, selecting only the <code>id</code>, <code>email</code>, and <code>name</code> fields. Finally, it returns the retrieved user data as a JSON response using <code>NextResponse.json()</code>.</p>
<p>Something is still missing. Can you guess? Any authenticated user can still request any resource by changing the URL path to the request they want. How? This leads us to object-level authorization.</p>
<h3 id="heading-object-level-authorization">Object-Level Authorization</h3>
<p>An object-level authorization ensures that a user can only access their own data (unless explicitly permitted).</p>
<p>The improvement to the code would be to add an ownership check. The adjustment ensures the API request checks if the requester is authenticated and owns the requested object. If either fails, access is denied.</p>
<pre><code class="language-tsx">export async function GET(
  req: Request,
  { params }: { params: { id: string } }
) {
  const session = await requireSession();

  if (!session) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  if (session.user.id !== params.id) {
    return NextResponse.json({ error: "Forbidden" }, { status: 403 });
  }

  const user = await db.user.findUnique({
    where: { id: params.id },
    select: { id: true, email: true, name: true },
  });

  return NextResponse.json({ user });
}
</code></pre>
<p>Let's take a look at what happened in the code, the <code>GET</code> handler first authenticates the request using <code>requireSession()</code>, returning a <code>401</code> response if no valid session exists. It then performs an authorization check by comparing <code>session.user.id</code> with <code>params.id</code>. If they do not match, it returns a <code>403 Forbidden</code> response, preventing users from accessing other users’ data. If both checks pass, it queries the database using <code>db.user.findUnique()</code> to retrieve the specified user and limits the result to selected fields. Finally, it sends the user data back as a JSON response. With this, you’ve enforced an <strong>object-level authorization</strong>.</p>
<h2 id="heading-how-to-design-safer-endpoints-apime">How to Design Safer Endpoints (<code>/api/me</code>)</h2>
<p>The safest approach in designing your endpoint is to eliminate the risk entirely. Instead of allowing users to specify IDs (<code>/api/users/:id</code>), use <code>/api/me</code>, because the server already knows the user’s identity from the session.</p>
<pre><code class="language-tsx">// app/api/me/route.ts
export async function GET() {
  const session = await requireSession();

  if (!session) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  const user = await db.user.findUnique({
    where: { id: session.user.id },
    select: { id: true, email: true, name: true },
  });

  return NextResponse.json({ user });
}
</code></pre>
<p>This approach makes sure that your API only returns data for the currently authenticated user. It first calls <code>requireSession()</code> to ensure the request is authenticated, returning a <code>401</code> response if no session exists. Instead of using a URL parameter, it reads the user’s ID directly from <code>session.user.id</code>, ensuring the user can only access their own data. It then calls <code>db.user.findUnique()</code> to retrieve that user from the database, selecting only specific fields, and returns the result as a JSON response.</p>
<p>You can be confident with this approach because the client cannot manipulate user IDs. The server gets the user identity from a trusted source, and the attack surface is reduced. This is called <code>secure-by-design</code> <strong>API model</strong>.</p>
<p>Now, you should clearly understand that authentication does not imply authorization. Hence,</p>
<ul>
<li><p>IDOR occurs when object ownership is not verified</p>
</li>
<li><p>Every API route that accepts an ID must validate access</p>
</li>
<li><p>Safer API design reduces vulnerability surface</p>
</li>
<li><p>Authorization must always run on the server</p>
</li>
</ul>
<h2 id="heading-mental-model-for-api-design">Mental Model for API Design</h2>
<p>When writing any API route, answer these questions:</p>
<ol>
<li><p>Who is making this request?</p>
</li>
<li><p>What object are they requesting?</p>
</li>
<li><p>Does policy allow them to access it?</p>
</li>
</ol>
<p>If you cannot clearly answer all three, your route may be vulnerable.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>IDOR vulnerabilities happen when APIs trust user-supplied identifiers without verifying ownership or permission.</p>
<p>To prevent them in Next.js, authenticate every private route, enforce object-level authorization, centralize authorization logic, and write tests for forbidden access.</p>
<p>Security is not about adding logins, it’s about enforcing security policy on every object access.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What Are JSON Web Tokens (JWT)? ]]>
                </title>
                <description>
                    <![CDATA[ When you’re working with any website, application, or API, you'll inevitably need to log in and authenticate your user base. One of the more commonly used methods of passing around authentication credentials from one system to another is using a JSON... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-are-json-web-tokens-jwt/</link>
                <guid isPermaLink="false">686c430b1a4ac707c0692874</guid>
                
                    <category>
                        <![CDATA[ JWT ]]>
                    </category>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ authorization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Tutorial ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Grant Riordan ]]>
                </dc:creator>
                <pubDate>Mon, 07 Jul 2025 21:58:35 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1751819356361/352ef68a-fa20-4a69-b666-393f7a17fa40.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>When you’re working with any website, application, or API, you'll inevitably need to log in and authenticate your user base. One of the more commonly used methods of passing around authentication credentials from one system to another is using a JSON Web Token (JWT).</p>
<p>In this article, you'll learn about:</p>
<ul>
<li><p>What a JSON Web Token (JWT) is</p>
</li>
<li><p>How JWTs are structured and created</p>
</li>
<li><p>Different JWT signing techniques and algorithms (Symmetric vs. Asymmetric)</p>
</li>
<li><p>How JWTs are used in real-world authentication flows</p>
</li>
<li><p>Important security best practices for using JWTs</p>
</li>
</ul>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-a-jwt">What is a JWT?</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-json-web-tokens-are-made-of-three-elements">JSON Web Tokens Are Made Of Three Elements</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-asymmetric-signing-rs256-explained">Asymmetric Signing (RS256) Explained</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-analogy-the-lock-and-key-for-asymmetric-signatures">Analogy: The Lock and Key for Asymmetric Signatures</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-symmetric-signing-hs256-hmac-with-sha-256">Symmetric Signing: HS256 (HMAC with SHA-256)</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-how-hs256-verification-works">How HS256 Verification Works</a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-jwts-in-action-a-typical-authentication-flow">JWTs in Action: A Typical Authentication Flow</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-jwt-security-best-practices-amp-considerations">JWT Security Best Practices &amp; Considerations</a></p>
</li>
</ul>
<h2 id="heading-what-is-a-jwt">What Is a JWT?</h2>
<blockquote>
<p>JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.<br>— Introduction to JWT by jwt.io</p>
</blockquote>
<p>While accurate, this definition can be a bit dense at first glance. Imagine you want to send someone a sealed, tamper-proof message. That's essentially what a JSON Web Token (JWT) is. It's a secure message, a special kind of message designed to be sent between two parties which can be assured it came from an expected sender.</p>
<p>Each JWT is digitally signed using either a <strong>secret code</strong> (for symmetric algorithms like HMAC) or a <strong>private key</strong> (for asymmetric algorithms like RSA or ECDSA).</p>
<p>This secret code or private key is known only to the system that issues the JWT (often called an <em>authentication provider</em>, like Auth0, AWS Cognito, or Firebase Auth, which handles user logins and identity).</p>
<p>This signature proves two things:</p>
<ol>
<li><p><strong>Authenticity:</strong> It proves the message really came from who it claims to be from.</p>
</li>
<li><p><strong>Integrity:</strong> It proves that the message hasn't been changed or tampered with since it was signed. If even one character is altered, the signature won't match, and you'll know something is wrong, meaning the contents of the JWT can't be trusted.</p>
</li>
</ol>
<h3 id="heading-json-web-tokens-are-made-of-three-elements">JSON Web Tokens Are Made of Three Elements</h3>
<p>JWTs are made up of 3 key parts:</p>
<ol>
<li><p>Header</p>
</li>
<li><p>Payload</p>
</li>
<li><p>Signature</p>
</li>
</ol>
<h4 id="heading-header">Header</h4>
<p>The header contains metadata information about the token. Think of it like a label on a package – it tells you what’s inside and how it was prepared.</p>
<p>Typically, the header contains:</p>
<p><code>alg</code>: This specifies the <strong>algorithm</strong> used to sign the JWT. Common algorithms are <code>HS256</code> (HMAC with SHA-256) or <code>RS256</code> (RSA with SHA-256).</p>
<p><code>typ</code>: This specifies the <strong>type</strong> of token, which is almost always <code>JWT</code> for standard JSON Web Tokens.</p>
<p><strong>Example (decoded):</strong></p>
<pre><code class="lang-json">{ 
  <span class="hljs-attr">"alg"</span>: <span class="hljs-string">"RS256"</span>,
  <span class="hljs-attr">"typ"</span>: <span class="hljs-string">"JWT"</span> 
}
</code></pre>
<h4 id="heading-payload">Payload</h4>
<p>This is the second part of the JWT, and it's where the real data or "claims" are stored. Claims are statements about an entity (usually a user) and any other additional data. Using the previous analogy of a package, think of it as the “contents” of the package.</p>
<p>There are three types of claims:</p>
<p><strong>1. Registered Claims:</strong> These are predefined claims that are recommended for common use cases. They are not mandatory but are very useful for interoperability. These include:</p>
<ul>
<li><p><code>iss</code> – issuer, who issued the token (for example, your application’s domain)</p>
</li>
<li><p><code>sub</code> – subject, the subject of the token (for example, a User’s ID)</p>
</li>
<li><p><code>aud</code> – audience, the audience of the token (that is, who the token is intended for – for example, a specific API)</p>
</li>
<li><p><code>exp</code> – <strong>expiration</strong>, the expiry date as a timestamp</p>
</li>
<li><p><code>iat</code> – issued at, when the token was issued as a timestamp</p>
</li>
<li><p><code>nbf</code> – not before, when the token becomes valid (that is, the token cannot be used or deemed valid before this timestamp)</p>
</li>
<li><p><code>jti</code> – JWT ID, a unique identifier for the token, useful for preventing replay attacks or blacklisting</p>
</li>
</ul>
<p><strong>2. Public Claims:</strong> These can be defined by anyone using JWTs. To avoid naming conflicts, it's a good practice to register them or define them using a unique identifier like a URI.</p>
<p><strong>3. Private Claims:</strong> These are custom claims created to share specific information between parties who agree on using them. They are entirely up to you and your application's needs.</p>
<p><strong>Example payload:</strong></p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"sub"</span>: <span class="hljs-string">"1234567890"</span>, <span class="hljs-comment">//  subject</span>
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"John Doe"</span>, <span class="hljs-comment">// private claim</span>
  <span class="hljs-attr">"admin"</span>: <span class="hljs-literal">true</span>, <span class="hljs-comment">// private claim / role</span>
  <span class="hljs-attr">"iat"</span>: <span class="hljs-number">1678886400</span>, <span class="hljs-comment">// Issued at a specific timestamp</span>
  <span class="hljs-attr">"exp"</span>: <span class="hljs-number">1678890000</span>  <span class="hljs-comment">// Expires at a specific timestamp</span>
}
</code></pre>
<p>Like the header, this JSON object is also <strong>Base64Url encoded</strong> (a URL-safe variant of Base64 encoding) to form the second part of the JWT string.</p>
<p><strong>Important Note:</strong> <em>The payload is</em> <strong><em>encoded*</em></strong>, not encrypted.* This means that anyone can easily decode the JWT and read its contents. Never put sensitive information (like passwords) directly into the payload unless the entire JWT itself is encrypted (which is a separate process called JWE - JSON Web Encryption). The security of a standard JWT comes entirely from the signature, which prevents tampering.</p>
<h4 id="heading-signature">Signature</h4>
<p>The signature, as we've already discussed, is the most important part of the JWT. Without it, there's no protection applied to the JWT, meaning no way to validate the origin of the token or its integrity.</p>
<p>The signature is created by taking the <strong>encoded header</strong>, the <strong>encoded payload</strong>, and a <strong>secret key</strong> (or a private key if using asymmetric algorithms like RSA). These are then run through the cryptographic algorithm specified in the header (<code>alg</code> field). For HS256, a shared secret key is used. For RS256, a private key is used to sign, and a corresponding public key is used to verify. We’ll get on to verification soon.</p>
<p>Think of it like a tamper-proof seal on your package, or even better, a wax seal on a letter. If you receive your letter and the wax seal has been broken, you'd naturally believe the contents of the letter may not be original and therefore can't be trusted.</p>
<p>In pseudo-code it would look like this:</p>
<p><code>Signature = Algorithm( Base64Url(Header) + "." + Base64Url(Payload), SecretKey )</code></p>
<p>The result of this signing process is the signature, which is also Base64Url encoded to form the third part of the JWT string.</p>
<p>At the end of the whole process your JWT would look like this:</p>
<p><code>base64EncodedHeader.base64EncodedPayload.base64EncodedSignature</code></p>
<h3 id="heading-asymmetric-signing-rs256-explained">Asymmetric Signing (RS256) Explained</h3>
<p>When a JWT uses an algorithm like RS256 (RSA Signature with SHA-256), it employs an <strong>asymmetric cryptographic</strong> process involving a <strong>public</strong> and <strong>private</strong> key pair. This is where the core magic of proving authenticity and integrity happens without needing to share a secret.</p>
<h4 id="heading-the-signing-process-by-the-issuer">The Signing Process (by the Issuer)</h4>
<p>The <strong>sender</strong> (the server that issues the JWT, like Auth0) possesses the <strong>private key</strong>. This key is kept absolutely secret and secure. Here are the steps:</p>
<ol>
<li><p><strong>Prepare the data:</strong> The server takes the header (which includes the algorithm) and the payload. It Base64Url-encodes them, and then concatenates them with a dot: <code>Base64Url(Header) + "." + Base64Url(Payload)</code>.</p>
<p> For example, with this header:</p>
<pre><code class="lang-json"> {
   <span class="hljs-attr">"typ"</span>: <span class="hljs-string">"JWT"</span>,
   <span class="hljs-attr">"alg"</span>: <span class="hljs-string">"RS256"</span>
 }
</code></pre>
<p> And this payload:</p>
<pre><code class="lang-json"> {
   <span class="hljs-attr">"sub"</span>: <span class="hljs-string">"1234567890"</span>,
   <span class="hljs-attr">"name"</span>: <span class="hljs-string">"John Doe"</span>,
   <span class="hljs-attr">"admin"</span>: <span class="hljs-literal">true</span>,
   <span class="hljs-attr">"iat"</span>: <span class="hljs-number">1751494086</span>,
   <span class="hljs-attr">"exp"</span>: <span class="hljs-number">1751497686</span>
 }
</code></pre>
<p> This would create a Base64Url-encoded <code>header.payload</code> string like the animated example below:</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751810671075/128fa652-fe2a-4413-a238-71531bfe67ae.gif" alt="Animated gif of the process converting header and payload to base64 encoded string" class="image--center mx-auto" width="800" height="587" loading="lazy"></p>
</li>
<li><p><strong>Calculate the hash:</strong> It then calculates a <strong>hash</strong> (using SHA-256 in this case) of this combined header and payload string.</p>
</li>
<li><p><strong>Sign the hash:</strong> Finally, it signs this hash using its private key. This cryptographically transformed hash is the signature part of the JWT.</p>
</li>
</ol>
<p>The JWT is then formed by concatenating the Base64Url-encoded header, the Base64Url-encoded payload, and the Base64Url-encoded signature, separated by dots: <code>header.payload.signature</code>.</p>
<p>The top segment below shows the full JWT token (header.payload.signature):</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751830473890/31da21a0-50db-4a48-b4c3-378c2ac1616a.png" alt="Image displaying the fully formed JWT token along with original header and payload" class="image--center mx-auto" width="2630" height="1100" loading="lazy"></p>
<h3 id="heading-the-verification-process">The Verification Process</h3>
<p>This is where the magic happens, and it's often a point of confusion. The public key doesn't "decrypt" the original data like a symmetric key does. Instead, it performs a unique <strong>verification</strong> process.</p>
<p>The receiver (the client or another server that needs to verify the JWT) possesses the <strong>public key</strong>. This key does <strong>not</strong> need to be kept secret – it can be freely distributed.</p>
<p>Here's a step-by-step explanation:</p>
<ol>
<li><p><strong>Separate the parts:</strong> The first thing the receiver does is split the incoming JWT string into its three Base64Url-encoded components: the Header, the Payload, and the Signature.</p>
</li>
<li><p><strong>Obtain the public key:</strong> The verifier needs the <strong>public key</strong> that corresponds to the private key used by the issuer. Public keys are often available via a <strong>JWKS (JSON Web Key Set) endpoint</strong> (for example, <code>your-domain.com/.well-known/jwks.json</code>).</p>
</li>
<li><p><strong>Re-create the data to be hashed:</strong> The receiver takes the received, Base64Url-encoded Header and the received, Base64Url-encoded Payload. It then combines them exactly as the issuer did: <code>EncodedHeader.EncodedPayload</code>.</p>
</li>
<li><p><strong>Compute a local hash (Hash A):</strong> This combined string is then put through the same hashing algorithm (for example, SHA-256) that was specified in the JWT's header. This produces a new, locally computed hash (let's call this <strong>"Hash A"</strong>). This local hash represents what the content <em>should</em> look like if it hasn't been tampered with.</p>
</li>
<li><p><strong>"Unsign" the received signature with the public key to get the original signed hash (Hash B):</strong> This is the core cryptographic step. The verifier uses the public key (obtained in step 2) to perform a mathematical operation on the received signature. This operation does <em>not</em> create a new signature for comparison. Instead, it effectively "unsigns" or "decrypts" the signature to reveal the <strong>original hash ("Hash B")</strong> that was produced by the issuer's private key.</p>
<ul>
<li><strong>Crucial Point:</strong> This process is for <strong>verifying authenticity</strong>, not decrypting confidential data. The public key confirms that the signature was indeed created by the corresponding private key, and as part of that confirmation, it returns the original hash that <em>was signed</em>.</li>
</ul>
</li>
<li><p><strong>Compare the hashes:</strong> The verifier now has two hashes:</p>
<ul>
<li><p><strong>Hash A:</strong> The hash it <strong>computed locally</strong> from the received header and payload (from step 4).</p>
</li>
<li><p><strong>Hash B:</strong> The original hash that was extracted from the received Signature using the public key (from step 5)</p>
</li>
</ul>
</li>
<li><p><strong>If Hash A matches Hash B:</strong> It proves two critical things:</p>
<ol>
<li><p><strong>Authenticity:</strong> The token was indeed signed by the legitimate holder of the corresponding private key (for example, Auth0).</p>
</li>
<li><p><strong>Integrity:</strong> The content of the header and payload has <strong>not been tampered with</strong> since it was originally signed. If even a single character in the header or payload were changed, Hash A would be different, and it would not match Hash B. In this case, the JWT is considered valid and its contents can be trusted.</p>
</li>
</ol>
</li>
<li><p><strong>If the hashes do NOT match:</strong> The token is considered invalid and <strong>must be rejected</strong>. This indicates either that the JWT was signed by an unauthorised party (a forged token) or that its header or payload has been altered after it was signed.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751813812291/de32c7b0-1f3c-4f26-995e-b5c618b104b3.png" alt=" Flow diagram of asymmetric verification process" class="image--center mx-auto" width="1649" height="2947" loading="lazy"></p>
<h3 id="heading-analogy-the-lock-and-key-for-asymmetric-signatures">Analogy: The Lock and Key for Asymmetric Signatures</h3>
<p><strong>Private Key:</strong> A special, unique key that can <strong>lock</strong> a box (create a signature). Only the owner has this key.</p>
<p><strong>Public Key:</strong> A widely distributed key that can <strong>test</strong> if a box was locked by the corresponding private key. It can't lock a new box, but it can confirm if an existing lock is authentic.</p>
<p>You don't re-lock the box with the public key. You use the public key to check if the existing lock (the signature) is genuine and corresponds to the contents of the box.</p>
<h2 id="heading-symmetric-signing-hs256-hmac-with-sha-256">Symmetric Signing: HS256 (HMAC With SHA-256)</h2>
<p>While RS256 uses a pair of keys (private for signing, public for verifying), many JWTs you'll encounter are signed symmetrically, most commonly with the HS256 algorithm. HS256 stands for <strong>HMAC (Hash-based Message Authentication Code) with SHA-256</strong>.</p>
<p>The fundamental difference here is the use of a single, shared secret key for <em>both</em> signing and verification.</p>
<h3 id="heading-how-hs256-signing-works">How HS256 Signing Works</h3>
<ol>
<li><p><strong>Shared secret key:</strong> The issuer (for example, your authentication provider) possesses a single, confidential secret key. This key is known <em>only</em> to the issuer and any parties (like your API) that need to verify the token.</p>
</li>
<li><p><strong>Combine header and payload:</strong> Just like with asymmetric signing, the issuer takes the Base64Url-encoded Header (which specifies <code>"alg": "HS256"</code>) and the Base64Url-encoded Payload, and <strong>joins</strong> them with a dot.</p>
</li>
<li><p><strong>Apply HMAC-SHA256:</strong> This combined string is then fed into the HMAC-SHA256 algorithm along with the secret key. The HMAC algorithm uses the secret key to create a unique hash (the signature) of the data. In pseudo-code, it looks like this:</p>
<p> <code>Signature = HMAC-SHA256( Base64Url(Header) + "." + Base64Url(Payload), SecretKey )</code></p>
</li>
<li><p><strong>Form the JWT:</strong> The resulting signature (which is also Base64Url-encoded) is appended to the header and payload with a dot, forming the complete JWT: <code>base64EncodedHeader.base64EncodedPayload.base64EncodedSignature</code>.</p>
</li>
</ol>
<h3 id="heading-how-hs256-verification-works">How HS256 Verification Works</h3>
<p>When a receiver gets an HS256-signed JWT, it goes through a verification process.</p>
<p>First, it separates the parts. The JWT is split into its three Base64Url-encoded components: Header, Payload, and Signature, as we did with asymmetric JWTs.</p>
<p>Then, it obtains the shared secret key. The receiver must also possess the <strong>exact same secret key</strong> that the issuer used to sign the token. This key is <em>not</em> publicly distributed like a public key – it must be securely provisioned to any entity that needs to verify tokens.</p>
<p>Next, it re-calculates the signature. The receiver does this by taking the received Base64Url-encoded Header and Payload, combining them, and then re-applying the HMAC-SHA256 algorithm using the <em>same secret key</em>. This produces a new, locally computed signature.</p>
<p>Finally, the receiver compares the signature it just calculated locally with the signature it received as part of the JWT.</p>
<ul>
<li><p><strong>If the two signatures match:</strong> The token is considered valid. This confirms its authenticity (it came from someone who knows the secret) and integrity (it hasn't been tampered with).</p>
</li>
<li><p><strong>If the signatures do NOT match:</strong> The token is invalid and must be rejected. This indicates either tampering or that it was signed with a different, unknown secret key.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751814851136/a73b7af6-e92d-40f3-b1e3-c4bd2406ede9.png" alt="Flow diagram of symmetric verification process" class="image--center mx-auto" width="1715" height="2977" loading="lazy"></p>
<h3 id="heading-key-differences-and-considerations">Key Differences and Considerations:</h3>
<ul>
<li><p><strong>Key management:</strong> With HS256, the secret key must be securely shared and kept confidential by <em>all</em> parties involved in both signing and verifying. This can be more challenging to manage securely at scale compared to the public/private key model, where only the private key needs strict secrecy.</p>
</li>
<li><p><strong>Performance:</strong> HS256 is generally faster to compute than asymmetric algorithms like RS256, making it suitable for high-volume scenarios where the secret key can be securely distributed.</p>
</li>
</ul>
<h2 id="heading-jwts-in-action-a-typical-authentication-flow">JWTs in Action: A Typical Authentication Flow</h2>
<p>Now that you understand how JWTs are structured and signed, let's look at how they're typically used in a real-world web application. This authentication flow is a common pattern you'd encounter.</p>
<h3 id="heading-step-1-user-logs-in"><strong>Step 1: User Logs In:</strong></h3>
<p>A user opens a client application (for example, a web browser, mobile app) and enters their login credentials (username and password).</p>
<p>The client sends these credentials securely (always over HTTPS!) to an <strong>authentication server</strong> (like Auth0, AWS Cognito, or your own backend's authentication endpoint).</p>
<h3 id="heading-step-2-authentication-server-issues-jwt"><strong>Step 2: Authentication Server Issues JWT:</strong></h3>
<p>Then the authentication server verifies the user's credentials. If valid, it generates a new JWT. This JWT contains claims (like the user's ID, roles, expiration time) in its payload and is digitally signed by the server's <strong>private key</strong> (for asymmetric algorithms like RS256) or <strong>secret key</strong> (for symmetric algorithms like HS256).</p>
<p>The server then sends this signed JWT back to the client.</p>
<h3 id="heading-step-3-client-stores-jwt"><strong>Step 3: Client Stores JWT:</strong></h3>
<p>The client receives the JWT and typically stores it in a secure location, such as browser memory storage, session storage, or an HTTP-only cookie. The method of storage depends on the client type and security considerations.</p>
<h3 id="heading-step-4-client-makes-api-calls"><strong>Step 4: Client Makes API Calls:</strong></h3>
<p>When the user wants to access a protected resource on a backend API (for example, their profile data, a private feed), the client includes the JWT in the request.</p>
<p>The standard way to do this is by sending the token in the <code>Authorization</code> header of the HTTP request, prefixed with the word <code>Bearer</code>:</p>
<p><code>Authorization: Bearer &lt;your_jwt_here&gt;</code></p>
<h3 id="heading-step-5-api-verifies-jwt-amp-authorises-request"><strong>Step 5: API Verifies JWT &amp; Authorises Request:</strong></h3>
<p>Now, the backend API receives the request and extracts the JWT from the <code>Authorization</code> header. The API then performs the JWT verification process depending on the algorithm:</p>
<ul>
<li><p>It checks the token's claims, especially the <code>exp</code> (expiration) claim, to ensure it's still valid.</p>
</li>
<li><p>If the token is valid, the API trusts the claims within the payload (for example, the user's ID) and proceeds to fulfill the request, potentially using the user's roles to determine if they have permission to access the requested resource.</p>
</li>
<li><p>If the token is invalid (bad signature, expired, and so on), the API rejects the request, typically with an HTTP 401 Unauthorised status.</p>
</li>
</ul>
<p>This flow is powerful because JWTs are <strong>stateless</strong>: once issued, the authentication server doesn't need to keep a record of active sessions. The API can verify the token independently, which simplifies scaling and reduces server load.</p>
<h2 id="heading-jwt-security-best-practices-and-considerations">JWT Security Best Practices and Considerations</h2>
<p>While JWTs offer powerful authentication capabilities, using them securely requires careful attention to best practices. Misconfigurations or oversight can lead to significant vulnerabilities.</p>
<h3 id="heading-always-use-httpstls"><strong>Always Use HTTPS/TLS:</strong></h3>
<p><strong>Crucial:</strong> JWTs are <strong>encoded, not encrypted, by default</strong>. This means anyone who intercepts the token during transmission can easily read its payload. Therefore, JWTs (and all authentication traffic) <strong>must always be transmitted over HTTPS (TLS)</strong> to encrypt the communication channel itself and prevent eavesdropping.</p>
<h3 id="heading-protect-your-signing-keys"><strong>Protect Your Signing Keys:</strong></h3>
<p>Whether it's a private key (for RS256) or a shared secret key (for HS256), these keys are paramount. If an attacker gains access to your signing key, they can forge valid JWTs, impersonate users, and compromise your system. Store these keys securely, preferably in dedicated key management services.</p>
<h3 id="heading-keep-access-tokens-short-lived-exp-claim"><strong>Keep Access Tokens Short-Lived (</strong><code>exp</code> claim):</h3>
<p>You should always set short expiration times (for example, 5-15 minutes) for your JWTs used as access tokens. This minimises the window of opportunity for an attacker if a token is compromised.</p>
<p>Since JWTs are stateless, they are hard to revoke immediately once issued. A short lifespan is your primary defense against compromised tokens.</p>
<h3 id="heading-implement-refresh-tokens-for-longer-sessions"><strong>Implement Refresh Tokens (for Longer Sessions):</strong></h3>
<p>To maintain user experience with short-lived access tokens, use <strong>refresh tokens</strong>. A refresh token is a separate, longer-lived token (usually stored more securely) that can be exchanged for a new, short-lived access token when the current one expires, without requiring the user to re-authenticate. Refresh tokens <em>can</em> be revoked by the server, offering better control.</p>
<h3 id="heading-never-put-sensitive-data-in-the-payload"><strong>Never Put Sensitive Data in the Payload:</strong></h3>
<p>Reiterating this crucial point: the JWT payload is Base64Url encoded, which is easily reversible. Do not put passwords, highly sensitive PII (Personally Identifiable Information), or confidential business data directly into the JWT payload. Only include non-sensitive or publicly available information, or data that's already encrypted by other means.</p>
<h3 id="heading-validate-all-claims-on-verification"><strong>Validate ALL Claims on Verification:</strong></h3>
<p>When verifying a JWT, don't just check the signature. Always validate all relevant claims, including:</p>
<ul>
<li><p><code>exp</code> (Expiration): Ensure the token hasn't expired.</p>
</li>
<li><p><code>iss</code> (Issuer): Verify the token came from the expected authentication server.</p>
</li>
<li><p><code>aud</code> (Audience): Ensure the token is intended for your specific API/application.</p>
</li>
<li><p><code>nbf</code> (Not Before): Check if the token is active yet.</p>
</li>
</ul>
<h3 id="heading-consider-token-revocation-for-critical-cases"><strong>Consider Token Revocation (for critical cases):</strong></h3>
<p>For situations requiring immediate revocation (for example, user password change, account deactivation), typical stateless JWTs are challenging. Strategies include:</p>
<ul>
<li><p>Short expiration times (as above).</p>
</li>
<li><p>A blacklist/revocation list: Store the <code>jti</code> (JWT ID) of revoked tokens in a database, checking this list on every request. This adds a stateful lookup but provides immediate revocation.</p>
</li>
</ul>
<h2 id="heading-thanks-for-reading">Thanks for reading!</h2>
<p>I hope you’ve found this tutorial useful, and as always if you want to ask any questions or hear about upcoming articles, you can always follow me on ‘X’, my handle is @grantdotdev and follow by clicking <a target="_blank" href="https://x.com/grantdotdev">here</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Implement RBAC in a Community Dashboard with Nuxt ]]>
                </title>
                <description>
                    <![CDATA[ Role Based Access Control (RBAC) is a useful authorization model for users with different access levels, such as those in a community dashboard. In this article, you’ll learn how to integrate this type of authorization with Permit.io in Nuxt. Table o... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/rbac-community-dashboard-with-nuxt/</link>
                <guid isPermaLink="false">6740bf4cd3bb67c73837c3ef</guid>
                
                    <category>
                        <![CDATA[ authorization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Nuxt.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Obum ]]>
                </dc:creator>
                <pubDate>Fri, 22 Nov 2024 17:28:44 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1732043730534/d88680d7-2590-4541-9120-40a43c3724ef.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Role Based Access Control (RBAC) is a useful authorization model for users with different access levels, such as those in a community dashboard.</p>
<p>In this article, you’ll learn how to integrate this type of authorization with Permit.io in Nuxt.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-table-of-contents">Table of Contents</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-the-difference-between-authentication-and-authorization">What is the Difference Between Authentication and Authorization?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-role-based-access-control-rbac">What is Role Based Access Control (RBAC)?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-are-the-benefits-of-using-authorization-as-a-service">What are the Benefits of Using Authorization As A Service?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-well-be-building">What We’ll Be Building</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-plan-rbac-with-permitio">How to Plan RBAC with</a> <a target="_blank" href="http://Permit.io">Permit.io</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-setup-permitio-in-nuxt">How to Setup</a> <a target="_blank" href="http://Permit.io">Permit.io</a> <a class="post-section-overview" href="#heading-how-to-setup-permitio-in-nuxt">in Nuxt</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-control-api-access-with-nuxt-middleware">How to Control API Access with Nuxt Middleware</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-test-rbac-in-the-community-dashboard">How to Test RBAC in the Community Dashboard</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-summary">Summary</a></p>
</li>
</ul>
<h2 id="heading-what-is-the-difference-between-authentication-and-authorization">What is the Difference Between Authentication and Authorization?</h2>
<p>When building applications, we often carry out authentication together with authorization. However, these two concepts are essentially different.</p>
<p>Authentication is verifying who a user is. During the authentication process, the user usually needs to log in with some identifier like email, phone, username, <em>with</em> Google, <em>with</em> Microsoft, and so on.</p>
<p>Authorization specifies the resources an authenticated user can view and what they can do in the application. Authorization tells a user's access rights after that user has been successfully authenticated.</p>
<p>For example, authentication is a user logging in with email and password or verifying their phone number with SMS. On the other hand, authorization is a writer creating and editing posts while only admins can approve and publish those posts.</p>
<p>The primary purpose of authentication is to establish a user's identity before granting them access to the system. The main goal of authorization is to control user actions and protect sensitive data or resources.</p>
<h2 id="heading-what-is-role-based-access-control-rbac">What is Role Based Access Control (RBAC)?</h2>
<p>Role-Based Access Control (RBAC) is an authorization model that you can use to manage and restrict access to system resources. It is based on the responsibilities, duties, or roles of users.</p>
<p>In RBAC, roles represent predefined sets of permissions that tell which actions a user can execute in an application. These roles are then assigned to users based on their job functions or responsibilities.</p>
<p>In common systems, anyone can assign permissions to individual users. In RBAC, we group permissions into roles. In turn, we assign these roles to users. For example, in a community dashboard, users might have roles like “Admin”, “Mentor”, or “Member”.</p>
<p>Aside from Role-Based Access Control, other popular authorization models exist such as Attribute-Based (ABAC) and Relationship-based (ReBAC) access controls. Attribute-Based Access Control uses a wide range of attributes and fits constantly changing systems. You could also combine it with Role-Based Access Control. For more info, see the <a target="_blank" href="https://www.permit.io/blog/rbac-vs-abac">Permit.io article on RBAC vs. ABAC</a>.</p>
<h2 id="heading-what-are-the-benefits-of-using-authorization-as-a-service">What are the Benefits of Using Authorization As A Service?</h2>
<p>You can build authorization models yourself in your application. But it may be time-consuming and cost-ineffective in the long run.</p>
<p>Using an external provider for authorization allows you to focus on the business logic in your applications. The benefits of outsourcing authorization are similar to using a third party like Auth0 or Firebase for Authentication.</p>
<p><a target="_blank" href="https://www.permit.io/blog/authorization-as-a-service">Authorization as a Service</a> provides a solution for managing user access and permissions in applications. When you use such an authorization solution, you enjoy enhanced security, granular access policies’ control, auto-scaling policies, reduced maintenance burden, faster upgrades, robust logging, and so on.</p>
<p>Permit.io is free to use for <a target="_blank" href="https://docs.permit.io/manage-your-account/workspace-usage/#maus--tenants-usage">up to a 1000 Monthly Active Users</a>, and has a UI and API for RBAC, ABAC, and ReBAC.</p>
<p>To Get Started with Permit.io:</p>
<ul>
<li><p>Go to <a target="_blank" href="https://app.permit.io">app.permit.io</a></p>
</li>
<li><p>Create an account</p>
</li>
<li><p>Create a workspace (in your account)</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1732037452876/4604ad72-c5cc-4e07-8f04-70ff4f3dbb8c.gif" alt="Demo of Getting Started with Permit.io" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h2 id="heading-what-well-be-building">What We’ll Be Building</h2>
<p>A community dashboard connects members within a community or forum. It is a platform where they can interact and access resources.</p>
<p>For demo purposes of RBAC, we’ll build a simple community dashboard that will include 3 types of content (entities): posts, materials, and announcements<em>.</em></p>
<p>The code we will be using is at <a target="_blank" href="https://github.com/obumnwabude/rbac-community-dashboard">https://github.com/obumnwabude/rbac-community-dashboard</a>. It consists of a Nuxt repo with its server configured for API calls and its front end built with Vue. Clone it with git and explore the code in an editor/IDE.</p>
<p>In the server, we will expose <em>GET, POST,</em> and <em>DELETE</em> endpoints for each entity (posts, materials, and announcements). In Nuxt, you can use the HTTP verb in the file name for the endpoint handler. So we can have <strong>posts.get.ts*</strong>,<em> <strong>posts.delete.ts</strong></em>,<em> <strong>materials.post.ts</strong></em>,* and so on, with each file containing the respective handler for the involved API endpoint.</p>
<p>In addition, the server files store and retrieve entities from JSON files. You should have a robust database setup in your product. For this project, we’ll use local JSON files to build a minimum reproducible example with focus on roles and authorization.</p>
<p>In the front end, we have four pages: three for the entities and a settings page. There is also a simple navigation: a bottom bar on smaller screens and a sidebar on wider ones. Each entity page shows a list of its items and a small form to create new ones.</p>
<p>Furthermore, the demo code uses <a target="_blank" href="https://tailwindcss.com/">tailwindcss</a> to style everything quickly. The settings page contains hardcoded user examples and roles for the demo. When testing, toggle the current user and see the roles in action.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1732031161755/36a4981c-bc1c-4156-afb8-05fab7d45ee7.gif" alt="Demo of Exploring the Community Dashboard" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>This article focuses on the parts of the code that deal with authorization. For the backend and the UI specifics of the community dashboard, we will only overview them. After that, we will deep dive into RBAC touchpoints.</p>
<h2 id="heading-how-to-plan-rbac-with-permitio">How to Plan RBAC with Permit.io</h2>
<p>Overall, planning authorization means mapping out “who” can carry out an action on “what<em>”</em>. In RBAC, we define roles and then assign them to users. The roles and users combo is the “who” part of the authorization.</p>
<p>The “what” side refers to the entities or resources that your application provides or manages. For this article’s example, we’ve chosen our resources as Posts, Materials, and Announcements.</p>
<p>Actions are user activity. The most common actions are “create<em>”, “</em>read<em>”, “</em>update<em>”,</em> and, “delete<em>”</em>. Per resource in your application, you can use these four actions, add more, or omit some. In this article, our resources will each have all four actions.</p>
<p>When planning authorization, define resources alongside the <em>“</em>actions” users can execute on each resource. After that, define roles. For each role, specify what actions a user holding that role can carry out on each resource. The mapping of resources, actions, and roles allows you to define the authorization policies of your application.</p>
<p>Permit.io makes it easy to edit policies. In Permit.io, you have an intuitive dashboard where you can create resources and their actions, create roles, and merge both with policy tables.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1732037510499/2c0acabb-e0b4-4002-8b7b-e2fd4dbb4777.gif" alt="Demo of Creating Resources and Actions in Permit.io" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>For our Community Dashboard example, we will create three roles with incremental access: member, mentor, and admin. For each role, we’ll allow read access to all resources. However, each role has different management access levels to the resources as follows:</p>
<ul>
<li><p><strong>Members</strong> can view all entities but can only create or delete posts.</p>
</li>
<li><p><strong>Mentors</strong> can view all entities and can create or delete posts and materials.</p>
</li>
<li><p><strong>Admins</strong> can create, view, and delete all entities.</p>
</li>
</ul>
<p>Assigning roles to actions in resources is the same as editing policies.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1732037619254/e8900675-18c0-429c-9840-3ba8c1c38a6c.gif" alt="Demo of Creating Roles and Editing Policies in Permit.io" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-setup-permitio-in-nuxt">How to Setup Permit.io in Nuxt</h2>
<p>For our demo project, you need to run <code>npm install</code>, create a <code>.env</code> file, and export your Permit token.</p>
<p>However, if you are building a new project, to setup Permit in Nuxt, first install it with npm.</p>
<pre><code class="lang-bash">npm install permitio
</code></pre>
<p>After that, create a <code>.env</code> file and add your PERMIT_TOKEN. Get the token from the dashboard.</p>
<pre><code class="lang-bash">PERMIT_TOKEN=permit_key_XXXXXXXXXXXXXXXXXXXXX
</code></pre>
<p>To make this token available to the Nuxt <code>runtimeConfig</code>, add it to the <code>nuxt.config.ts</code> file. Also, add <code>permitio</code> (alongside other dependencies) in the <code>transpile</code> array of the build property of the Nuxt config file.</p>
<p>This addition is to account for Nuxt’s specific optimizations. Your <code>nuxt.config.ts</code> file should look like the following:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// https://nuxt.com/docs/api/configuration/nuxt-config</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> defineNuxtConfig({
  <span class="hljs-comment">// ... other properties</span>

  build: {
    transpile: [<span class="hljs-string">'axios'</span>, <span class="hljs-string">'permitio'</span>, <span class="hljs-string">'pino'</span>]
  },
  runtimeConfig: {
    permitToken: process.env.PERMIT_TOKEN
  }
});
</code></pre>
<p>After these, Permit.io should be available to your server code in Nuxt. You can now use in it middleware code to check for permissions.</p>
<h2 id="heading-how-to-control-api-access-with-nuxt-middleware">How to Control API Access with Nuxt Middleware</h2>
<p>In simple terms, middleware is code that runs before a target handler. In Nuxt, you can add middleware for API endpoints by creating necessary files in a <code>middleware</code> directory contained in the top-level <code>server</code> directory.</p>
<p>Since we are dealing with permissions, we will name our middleware file <code>permissions.ts</code>. Here, you’ll check if a user is permitted to take an action on a given resource.</p>
<p>Permit.io makes this easy with a simple <code>.check</code> method that returns a Boolean indicating if the user is permitted.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">await</span> permit.check(user, action, resource);
</code></pre>
<p>For this simple example community dashboard, our middleware code will first try to determine the user and action from the request properties. The example code achieves that in crude ways. They are enough to explain the concept and you should use more robust industry-standard methods for this.</p>
<p>After that, in the example code below, we construct the Permit object using our permit token and the default public PDP (Policy-Decision-Point microservice)’s endpoint. The <a target="_blank" href="https://github.com/permitio/PDP">Permit PDP is open-source.</a> If you wish, you can set up your local/personal PDP by following the steps <a target="_blank" href="https://docs.permit.io/how-to/deploy/deploy-to-production">here</a>.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Permit } <span class="hljs-keyword">from</span> <span class="hljs-string">'permitio'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> defineEventHandler(<span class="hljs-keyword">async</span> (event) =&gt; {
  <span class="hljs-comment">// Only check permissions if the request is a POST or DELETE request</span>
  <span class="hljs-keyword">const</span> { method, path } = event;
  <span class="hljs-keyword">if</span> (method !== <span class="hljs-string">'POST'</span> &amp;&amp; method !== <span class="hljs-string">'DELETE'</span>) <span class="hljs-keyword">return</span>;

  <span class="hljs-comment">// Ensure authorization header is present</span>
  <span class="hljs-keyword">let</span> authorization = event.node.req.headers[<span class="hljs-string">'authorization'</span>];
  <span class="hljs-keyword">if</span> (!authorization) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Unauthorized'</span>);

  <span class="hljs-comment">// Extract the user from the authorization header. This is for example</span>
  <span class="hljs-comment">// purposes only. In a real application, you would use a JWT library or</span>
  <span class="hljs-comment">// better authentication methods in your API.</span>
  <span class="hljs-keyword">const</span> user = authorization.split(<span class="hljs-string">' '</span>)[<span class="hljs-number">1</span>];
  <span class="hljs-keyword">if</span> (!user) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Unauthorized'</span>);

  <span class="hljs-comment">// Extract the resource from the path. This is for example purposes only.</span>
  <span class="hljs-keyword">let</span> resource = path.split(<span class="hljs-string">'/'</span>).reverse()[<span class="hljs-number">0</span>]; <span class="hljs-comment">// get the last part of the path</span>
  resource = resource.slice(<span class="hljs-number">0</span>, <span class="hljs-number">-1</span>); <span class="hljs-comment">// remove the trailing 's' </span>
  <span class="hljs-comment">// Capitalize the first letter</span>
  resource = resource.charAt(<span class="hljs-number">0</span>).toUpperCase() + resource.slice(<span class="hljs-number">1</span>);

  <span class="hljs-comment">// Set the action on the resource from the request method. </span>
  <span class="hljs-comment">// This is for example purposes only. In a real application, you would</span>
  <span class="hljs-comment">// have a more robust way to determine the action. </span>
  <span class="hljs-keyword">const</span> action = method === <span class="hljs-string">'POST'</span> ? <span class="hljs-string">'create'</span> : <span class="hljs-string">'delete'</span>;

  <span class="hljs-comment">// Construct the Permit object. Use the token from runtime config.</span>
  <span class="hljs-keyword">const</span> config = useRuntimeConfig(event);
  <span class="hljs-keyword">const</span> permit = <span class="hljs-keyword">new</span> Permit({
    pdp: <span class="hljs-string">'https://cloudpdp.api.permit.io'</span>,
    token: config.permitToken
  });

  <span class="hljs-comment">// Check if the user is permitted to create the resource. </span>
  <span class="hljs-comment">// If not, throw an error.</span>
  <span class="hljs-keyword">const</span> isPermitted = <span class="hljs-keyword">await</span> permit.check(user, action, resource);
  <span class="hljs-keyword">if</span> (!isPermitted) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Unauthorized'</span>);
});
</code></pre>
<p>As you can see, if the Permit checker fails, an error will be thrown. This will make Nuxt to prevent unauthorized resource management in your system. Such separation of concerns is efficient, especially in Authorization.</p>
<h2 id="heading-how-to-test-rbac-in-the-community-dashboard">How to Test RBAC in the Community Dashboard</h2>
<p>The settings page works together with the <code>stores/permissions.ts</code> file to complete the flow in the front end. We hardcoded the roles and the “user IDs” to ease toggling and testing. You definitely won’t have this in a production application. You can <a target="_blank" href="https://docs.permit.io/integrations/feature-flagging/casl/">integrate CASL for permission checks in a frontend</a>.</p>
<p>In this demo community dashboard, the UI touchpoints only allow edits of entities for which the acting user has the right roles. In other words, you can only add or delete an entity if the current role in the settings page allows that. Let’s see this in action.</p>
<p>In the Permit.io dashboard, create three test users: “example-member”, “example-mentor”, and “example-admin”. Assign the respective roles to each user.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1732037709104/0cb7b666-8597-4839-802b-e79e0434572a.gif" alt="Demo of Creating Test Users and assigning Roles in Permit.io" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Start up the Nuxt app by running <code>npm run dev</code>. Visit <code>localhost:3000</code> in your browser and explore the role-based authorization in the demo community dashboard.</p>
<p>You can see that when you set the Current User to admin, you can create and delete announcements, but when set to guest, you can only view entities and not manage them. With this, we’ve fully implemented authorization.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1732031066634/54310991-3ce9-4736-8735-c2776e4f6d82.gif" alt="Demo of Testing Roles in the Community Dashboard" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h2 id="heading-summary">Summary</h2>
<p>You can be more efficient in building your application by focusing on business logic and outsourcing crucial parts like authorization.</p>
<p>In this article, you learned how you can use an authorization solution (Permit.io) to implement Role-Based Access Control in a demo community dashboard with Nuxt. You can also use Permit in any other kind of application (not just community dashboards).</p>
<p>When planning authorization, define resources alongside the <em>“</em>actions” users can execute on each resource. After that, define roles as the permissions the users can have.</p>
<p>Cheers!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Implement Fine-Grained Authorization in Java and SpringBoot ]]>
                </title>
                <description>
                    <![CDATA[ Securing your application goes beyond simply granting or denying access at the surface level. As a developer, you need to implement fine-grained authorization (FGA) to manage permissions at a more detailed, granular level. FGA allows you to set up de... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/fine-grained-authorization-in-java-and-springboot/</link>
                <guid isPermaLink="false">671a85db0db570158155ec00</guid>
                
                    <category>
                        <![CDATA[ Java ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Springboot ]]>
                    </category>
                
                    <category>
                        <![CDATA[ authorization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Docker ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Developer ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Developer Tools ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ankur Tyagi ]]>
                </dc:creator>
                <pubDate>Thu, 24 Oct 2024 17:37:31 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1729783227124/9725e8cf-553d-42c3-a823-5215e8d4d0e9.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Securing your application goes beyond simply granting or denying access at the surface level. As a developer, you need to implement <code>fine-grained authorization</code> (FGA) to manage permissions at a more detailed, granular level.</p>
<p>FGA allows you to set up detailed access controls that specify who can do what and under which conditions.</p>
<p>In this tutorial, you will learn how to implement <code>fine-grained authorization</code> in Java and Spring Boot using <a target="_blank" href="https://permit.io/">Permit.io</a>.</p>
<p>Here is the <a target="_blank" href="https://github.com/tyaga001/java-spring-fine-grained-auth">source code</a> (remember to give it a star ⭐).</p>
<p>I hope you enjoyed my previous <a target="_blank" href="https://www.freecodecamp.org/news/how-i-built-a-custom-video-conferencing-app-with-stream-and-nextjs/">blog</a> about building a custom video conferencing app with Stream and Next.js. These blogs reflect my journey in creating DevTools Academy, a platform designed to help developers discover amazing developer tools.</p>
<p>This tutorial is another effort to introduce you to a super helpful developer tool that I recently explored.</p>
<h2 id="heading-table-of-contents"><strong>Table of Contents:</strong></h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-permit">What is Permit</a>?</p>
</li>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-fine-grained-authorization">What is Fine-Grained Authorization</a>?</p>
<ul>
<li><p><a class="post-section-overview" href="#heading-role-based-access-control-rbac">Role-Based Access Control (RBAC)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-attribute-based-access-control-abac">Attribute-Based Access Control (ABAC)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-relationship-based-access-control-rebac">Relationship-Based Access Control (ReBAC)</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-implement-fine-grained-authorization">How to Implement Fine-Grained Authorization</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-implementing-role-based-access-control">Implementing Role-Based Access Control</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-implementing-attribute-based-access-control">Implementing Attribute-Based Access Control</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-implementing-relationship-based-access-control">Implementing Relationship-Based Access Control</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-implement-fga-in-java-and-springboot">How to Implement FGA in Java and SpringBoot</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-step-1-setting-up-the-e-commerce-application">Step 1: Setting Up the E-commerce Application</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-2-get-your-environment-api-key">Step 2: Get your Environment API Key</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-3-deploy-policy-decision-point-pdp">Step 3: Deploy Policy Decision Point (PDP)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-4-running-the-app">Step 4: Running the App</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-next-steps">Next Steps</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-before-we-end">Before We End...</a></li>
</ul>
</li>
</ul>
<h2 id="heading-what-is-permit"><strong>What is</strong> Permit?</h2>
<blockquote>
<p><a target="_blank" href="https://www.permit.io">Permit.io</a> is a full stack, plug-and-play application-level authorization solution that allows you to implement a <code>secure</code>, <code>flexible</code>, <code>authorization</code> layer within minutes, so you can focus on what matters most.</p>
</blockquote>
<p><a target="_blank" href="https://www.permit.io"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729499767197/6e2b4312-8986-493e-9453-3b67e6aad155.png" alt="what is permit - screenshot of homepage" class="image--center mx-auto" width="600" height="400" loading="lazy"></a></p>
<h2 id="heading-prerequisites"><strong>Prerequisites</strong></h2>
<p>To fully understand the tutorial, you need to have a basic understanding of <code>Java</code> and <code>Spring Boot</code>. You’ll also need the following:</p>
<ul>
<li><p><a target="_blank" href="http://Permit.io"><strong>Permit.io</strong></a>: A developer tool that simplifies the implementation of FGA.</p>
</li>
<li><p><strong>Spring Boot Starter Web</strong>: Provides essential components for building web applications, including RESTful APIs.</p>
</li>
<li><p><strong>Gradle</strong>: A build tool for managing dependencies.</p>
</li>
<li><p><strong>JDK 11 or later</strong>: The Java Development Kit version required to compile and run your Spring Boot app.</p>
</li>
<li><p><strong>Postman or cURL</strong>: Tools for testing your <code>API</code> endpoints.</p>
</li>
</ul>
<h2 id="heading-what-is-fine-grained-authorization"><strong>What is Fine-Grained Authorization?</strong></h2>
<p><a target="_blank" href="https://www.permit.io/blog/what-is-fine-grained-authorization-fga">Fine-grained authorization</a> offers access control to resources by determining who can access them, to what extent, and under specified conditions.</p>
<p>Contrary to coarse-grained authorization (that handles access based on categories like <code>user roles</code> such as "<code>admin</code>" or "<code>user</code>"), fine-grained authorization gives you the flexibility to define access at a granular level, for specific resources or actions and even attributes. </p>
<p>In <code>Fine Grained Authorization</code> there exist 3 types of policy models for managing authorization; <strong>Role Based Access Control (RBAC)</strong>, <strong>Attribute Based Access Control (ABAC)</strong>, and <strong>Relationship-Based Access Control (ReBAC)</strong>.</p>
<p>Let's take a look, at each of these approaches and see how you can implement them in your application.</p>
<h3 id="heading-role-based-access-control-rbac"><strong>Role-Based Access Control (RBAC)</strong></h3>
<p><a target="_blank" href="https://www.permit.io/blog/what-is-rebac">RBAC</a> is a security approach that controls resource access based on the roles of users within an organization. This model streamlines permissions by organizing users into roles and managing access control according to these defined roles.</p>
<p><strong>Key Concepts in RBAC:</strong></p>
<p><strong>Users:</strong> People who use the system such as employees or customers.</p>
<p><strong>Roles:</strong> A set of permissions or access privileges assigned to a group of users based on their responsibilities or tasks such as admin, manager, or customer.</p>
<p><strong>Permissions:</strong> The rights granted to users for interacting with resources, such as read, write, or delete.</p>
<h3 id="heading-attribute-based-access-control-abac"><strong>Attribute-Based Access Control (ABAC)</strong></h3>
<p><a target="_blank" href="https://www.permit.io/blog/what-is-abac">ABAC</a> is a versatile and adaptive access control model that decides who can or cannot access resources based on attributes, like user details. The ABAC model allows you to define fine-grained authorization based on user attributes.</p>
<p><strong>Key Concepts in ABAC:</strong></p>
<p><strong>Attributes:</strong> Characteristics or properties used to make access control decisions. Attributes are typically categorized into:</p>
<ul>
<li><p><strong>User Attributes:</strong> Information about the user (for example, role, department, job title, age, and so on).</p>
</li>
<li><p><strong>Resource Attributes:</strong> Characteristics of the resource (for example, file type, data classification level, creation date, owner).</p>
</li>
<li><p><strong>Action Attributes:</strong> The action the user is trying to perform (for example, read, write, delete, approve).</p>
</li>
<li><p><strong>Environmental Attributes:</strong> Contextual information about the access request (for example, time of day, location, device type, IP address).</p>
</li>
</ul>
<h3 id="heading-relationship-based-access-control-rebac"><strong>Relationship-Based Access Control (ReBAC)</strong></h3>
<p>ReBAC is an access control system that grants permissions to access resources based on the relationship between entities within a system. The approach emphasizes defining and managing access control by mapping out how users relate to resources and other entities such as organizations or groups.</p>
<p><strong>Key Concepts of ReBAC:</strong></p>
<p><strong>Entities:</strong> Users, resources (such as files and documents), and other entities, such as groups or organizational units.</p>
<p><strong>Relationships:</strong> The connections that specify the relationship between two entities. A user might be the "owner" of a document or a "member" of a team, for instance.</p>
<p><strong>Policies:</strong> Rules that use relationships to determine access rights. A user can access a resource or execute an action on it if they have a particular relationship with it.</p>
<h2 id="heading-how-to-implement-fine-grained-authorization"><strong>How to Implement Fine-Grained Authorization</strong></h2>
<p>Now that you have a basic understanding of <code>RBAC</code>, <code>ABAC</code>, and <code>ReBAC</code>, let’s see how we can implement these models in an e-commerce app.</p>
<h3 id="heading-implementing-role-based-access-control"><strong>Implementing Role-Based Access Control</strong></h3>
<p><strong>Step 1:</strong> Navigate to <a target="_blank" href="http://Permit.io">Permit.io</a>, and then create an account and your workspace.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729494514537/a49035e8-1eb2-495f-acee-6ac212d0076e.png" alt="Permit.io - create your workspace page" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>By default, you should see a project that includes two environments: <code>Development</code> and <code>Production</code>. </p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><strong><em>Note:</em></strong><em> You need to define and test your policies in the development environment before deploying them to production.</em></div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729494835226/8d0e6841-09e7-44e2-89fb-1ec3bacb316d.png" alt="Permit.io - project dashboard" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p><strong>Step 2:</strong> Create a resource named <strong>Products</strong>. To create the resource, open the <strong>Policy</strong> tab on the left sidebar and then open the <strong>Resources</strong> tab at the top. After that, click the <strong>Create a Resource</strong> button and then create a resource called <strong>Products</strong> with actions <code>read</code>, <code>create</code>, <code>update</code>, and <code>delete</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729495042599/91660d3d-eafe-4874-aeb2-50bf88c5a291.png" alt="Permit.io - how to add a new resource" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p><strong>Step 3:</strong> Create another resource called <strong>Reviews</strong> with actions <code>read</code>, <code>create</code>, <code>update</code>, and <code>delete</code>.</p>
<p><strong>Step 4:</strong> Open the <strong>Policy Editor</strong> tab. You’ll see that 3 roles named <code>admin</code>, <code>editor</code>, and <code>viewer</code> were created.</p>
<ul>
<li><p>Role admin has permission to <code>create</code>, <code>delete</code>, <code>read</code>, or <code>update</code> a product or a review.</p>
</li>
<li><p>Role <code>editor</code> has permission to <code>create</code>, <code>read</code>, or <code>update</code> a <code>product</code> or a <code>review</code> but not <code>delete</code> any.</p>
</li>
<li><p>Role <code>viewer</code> has permission to <code>create</code> and <code>read</code> a product or a <code>review</code> but not <code>delete</code> or <code>update</code> any.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729495227714/38553c90-5cc0-4fa0-a116-2f5051b5ebb8.png" alt="Permit.io - Policy editor" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-implementing-attribute-based-access-control"><strong>Implementing Attribute-Based Access Control</strong></h3>
<p><strong>Step 1:</strong> Open the <strong>Resources</strong> tab, then click the <strong>Add Attributes</strong> button.</p>
<ul>
<li><p>Add an attribute called <strong>vendor</strong></p>
</li>
<li><p>Add an attribute called the <strong>customer</strong></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729495417262/94a09532-83b3-496c-8fef-6ee7c836a211.png" alt="Permit.io - edit resource" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p><strong>Step 2:</strong> Open the ABAC Rules tab, then create a new ABAC Resource Set called <strong>Own Products</strong> that depends on the Products resource. After that, add a condition that gives permissions only to the user who created a product based on the vendor attribute.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729495597939/d528f47f-710a-4bd6-b13a-1cf3a3c49031.png" alt="Permit.io - create your resource set page" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p><strong>Step 3:</strong> Create another ABAC Resource Set called <strong>Own Reviews</strong> that depends on the Reviews resource.</p>
<h3 id="heading-implementing-relationship-based-access-control"><strong>Implementing Relationship-Based Access Control</strong></h3>
<p><strong>Step 1:</strong> Open the Resources tab and edit the Products resource. Add role <code>vendor</code> in the <code>ReBAC</code> options section. Then set products as parent of reviews in the relations section.</p>
<p><strong>Step 2:</strong> Edit the Reviews resource by adding role customer in the <code>ReBAC</code> options section, as shown below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729497355241/4f1a6235-7181-468a-82ce-c727df517604.png" alt="Permit.io - ABAC edit resource" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p><strong>Step 3:</strong> Go to <code>Policy</code> <code>Editor</code> tab and add:</p>
<ul>
<li><p>role <code>vendor</code> permission to update and delete own products.</p>
</li>
<li><p>role <code>customer</code> permission to update and delete their own reviews on products.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729497438508/935f79b7-3789-4047-b7b5-73e82654b617.png" alt="Permit.io - Policy editor" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-implement-fga-in-java-and-springboot"><strong>How to Implement FGA in Java and SpringBoot</strong></h2>
<p>Now that we have defined <code>RBAC</code>, <code>ABAC</code>, and <code>ReBAC</code> policies in the Permit.io web interface, let’s learn how to enforce them in an E-Commerce Management System application using the Permit.io API.</p>
<p>There’s a lot of code coming up, so make sure you read through the extensive comments I’ve left throughout each code block. These will help you understand more fully what’s going on in this code.</p>
<h3 id="heading-step-1-setting-up-the-e-commerce-application"><strong>Step 1: Setting Up the E-commerce Application</strong></h3>
<p>To set up the e-commerce application and git clone the source code.</p>
<pre><code class="lang-powershell">git clone https://github.com/tyaga001/java<span class="hljs-literal">-spring</span><span class="hljs-literal">-fine</span><span class="hljs-literal">-grained</span><span class="hljs-literal">-auth</span>.git
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Then open the code in your Java IDE.&nbsp;I used <a target="_blank" href="https://www.jetbrains.com/idea/">JetBrains</a> for all my work.</div>
</div>

<h4 id="heading-installing-permit-package-sdk"><strong>Installing Permit package SDK</strong></h4>
<p>To install the Permit package SDK, you add the SDK under the dependencies block in the <code>build.graddle</code> file.</p>
<pre><code class="lang-java">## Dependencies

To set up the necessary dependencies <span class="hljs-keyword">for</span> your Spring Boot project, include the following in your `build.gradle` file:

```groovy
dependencies {
    implementation <span class="hljs-string">'org.springframework.boot:spring-boot-starter-web'</span>
    implementation <span class="hljs-string">'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0'</span>
    developmentOnly <span class="hljs-string">'org.springframework.boot:spring-boot-devtools'</span>
    testImplementation <span class="hljs-string">'org.springframework.boot:spring-boot-starter-test'</span>
    testRuntimeOnly <span class="hljs-string">'org.junit.platform:junit-platform-launcher'</span>

    <span class="hljs-comment">// Add this line to install the Permit.io Java SDK in your project</span>
    implementation <span class="hljs-string">'io.permit:permit-sdk-java:2.0.0'</span>
}
</code></pre>
<h4 id="heading-initializing-the-permit-sdk"><strong>Initializing the Permit SDK</strong></h4>
<p>You can initialize the Permit <code>SDK</code> Client using the code below:</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.boostmytool.store.config;

<span class="hljs-keyword">import</span> io.permit.sdk.Permit;
<span class="hljs-keyword">import</span> io.permit.sdk.PermitConfig;
<span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Value;
<span class="hljs-keyword">import</span> org.springframework.context.annotation.Bean;
<span class="hljs-keyword">import</span> org.springframework.context.annotation.Configuration;

<span class="hljs-meta">@Configuration</span>  <span class="hljs-comment">// Marks this class as a configuration class for Spring IoC</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PermitClientConfig</span> </span>{

    <span class="hljs-meta">@Value("${permit.api-key}")</span>  <span class="hljs-comment">// Inject Permit API key from application properties</span>
    <span class="hljs-keyword">private</span> String apiKey;

    <span class="hljs-meta">@Value("${permit.pdp-url}")</span>  <span class="hljs-comment">// Inject Permit PDP (Policy Decision Point) URL from application properties</span>
    <span class="hljs-keyword">private</span> String pdpUrl;

    <span class="hljs-comment">/**
     * Creates a Permit client bean with custom configuration
     * <span class="hljs-doctag">@return</span> Permit client instance
     */</span>
    <span class="hljs-meta">@Bean</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Permit <span class="hljs-title">permit</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Permit(
                <span class="hljs-keyword">new</span> PermitConfig.Builder(apiKey)  <span class="hljs-comment">// Initialize PermitConfig with API key</span>
                        .withPdpAddress(pdpUrl)   <span class="hljs-comment">// Set the PDP address</span>
                        .withDebugMode(<span class="hljs-keyword">true</span>)      <span class="hljs-comment">// Enable debug mode for detailed logging</span>
                        .build()                  <span class="hljs-comment">// Build the PermitConfig object</span>
        );
    }
}
</code></pre>
<h4 id="heading-syncing-users-with-sdk"><strong>Syncing Users with SDK</strong></h4>
<p>To start enforcing permissions, you should first sync a user to Permit, and then assign them a role.</p>
<p>In the code below, the <strong>UserService</strong> class provides methods for user login, signup, role assignment, and authorization, with exception handling for possible errors when interacting with the Permit API.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.boostmytool.store.service;

<span class="hljs-keyword">import</span> com.boostmytool.store.exception.ForbiddenAccessException;
<span class="hljs-keyword">import</span> com.boostmytool.store.exception.UnauthorizedException;
<span class="hljs-keyword">import</span> io.permit.sdk.Permit;
<span class="hljs-keyword">import</span> io.permit.sdk.api.PermitApiError;
<span class="hljs-keyword">import</span> io.permit.sdk.api.PermitContextError;
<span class="hljs-keyword">import</span> io.permit.sdk.enforcement.Resource;
<span class="hljs-keyword">import</span> io.permit.sdk.enforcement.User;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Service;

<span class="hljs-keyword">import</span> java.io.IOException;

<span class="hljs-meta">@Service</span>  <span class="hljs-comment">// Marks this class as a Spring service, making it a candidate for component scanning</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserService</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> Permit permit;

    <span class="hljs-comment">// Constructor injection for the Permit SDK</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">UserService</span><span class="hljs-params">(Permit permit)</span> </span>{
        <span class="hljs-keyword">this</span>.permit = permit;
    }

    <span class="hljs-comment">/**
     * Simulates user login by creating and returning a Permit User object.
     * 
     * <span class="hljs-doctag">@param</span> key User's unique key
     * <span class="hljs-doctag">@return</span> User object
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Object <span class="hljs-title">login</span><span class="hljs-params">(String key)</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> User.Builder(key).build();
    }

    <span class="hljs-comment">/**
     * Handles user signup by creating and syncing a new Permit User.
     * 
     * <span class="hljs-doctag">@param</span> key User's unique key
     * <span class="hljs-doctag">@return</span> Created and synced User object
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> User <span class="hljs-title">signup</span><span class="hljs-params">(String key)</span> </span>{
        <span class="hljs-keyword">var</span> user = <span class="hljs-keyword">new</span> User.Builder(key).build();
        <span class="hljs-keyword">try</span> {
            permit.api.users.sync(user);  <span class="hljs-comment">// Syncs the new user with the Permit service</span>
        } <span class="hljs-keyword">catch</span> (PermitContextError | PermitApiError | IOException e) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"Failed to create user"</span>, e);  <span class="hljs-comment">// Handles exceptions during user creation</span>
        }
        <span class="hljs-keyword">return</span> user;
    }

    <span class="hljs-comment">/**
     * Assigns a role to the user within the "default" environment.
     * 
     * <span class="hljs-doctag">@param</span> user User object to assign the role to
     * <span class="hljs-doctag">@param</span> role Role to be assigned
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">assignRole</span><span class="hljs-params">(User user, String role)</span> </span>{
        <span class="hljs-keyword">try</span> {
            permit.api.users.assignRole(user.getKey(), role, <span class="hljs-string">"default"</span>);  <span class="hljs-comment">// Assigns role in the "default" environment</span>
        } <span class="hljs-keyword">catch</span> (PermitApiError | PermitContextError | IOException e) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"Failed to assign role to user"</span>, e);  <span class="hljs-comment">// Handles exceptions during role assignment</span>
        }
    }

    <span class="hljs-comment">/**
     * Checks if the user is authorized to perform a specific action on a resource.
     * 
     * <span class="hljs-doctag">@param</span> user User object requesting authorization
     * <span class="hljs-doctag">@param</span> action Action to be authorized
     * <span class="hljs-doctag">@param</span> resource Resource on which the action will be performed
     * <span class="hljs-doctag">@throws</span> UnauthorizedException if user is not logged in
     * <span class="hljs-doctag">@throws</span> ForbiddenAccessException if user is denied access
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">authorize</span><span class="hljs-params">(User user, String action, Resource resource)</span> </span>{
        <span class="hljs-keyword">if</span> (user == <span class="hljs-keyword">null</span>) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UnauthorizedException(<span class="hljs-string">"Not logged in"</span>);  <span class="hljs-comment">// Throws exception if user is not logged in</span>
        }
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">var</span> permitted = permit.check(user, action, resource);  <span class="hljs-comment">// Performs authorization check</span>
            <span class="hljs-keyword">if</span> (!permitted) {
                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ForbiddenAccessException(<span class="hljs-string">"Access denied"</span>);  <span class="hljs-comment">// Throws exception if access is denied</span>
            }
        } <span class="hljs-keyword">catch</span> (PermitApiError | IOException e) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"Failed to authorize user"</span>, e);  <span class="hljs-comment">// Handles exceptions during authorization</span>
        }
    }
}
</code></pre>
<p>Then in the code below, the <strong>UserController</strong> class exposes REST API endpoints for user signup and role assignment. It interacts with the UserService class to handle user-related business logic and provides appropriate HTTP responses.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.boostmytool.store.controllers;

<span class="hljs-keyword">import</span> com.boostmytool.store.exception.UnauthorizedException;
<span class="hljs-keyword">import</span> com.boostmytool.store.service.UserService;
<span class="hljs-keyword">import</span> io.permit.sdk.enforcement.User;
<span class="hljs-keyword">import</span> jakarta.servlet.http.HttpServletRequest;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.PostMapping;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.RequestBody;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.RequestMapping;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.RestController;

<span class="hljs-meta">@RestController</span>  <span class="hljs-comment">// Indicates that this class handles HTTP requests and returns JSON responses</span>
<span class="hljs-meta">@RequestMapping("/api/users")</span>  <span class="hljs-comment">// Base URL path for all user-related operations</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserController</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> UserService userService;

    <span class="hljs-comment">// Constructor injection of UserService, containing business logic for user operations</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">UserController</span><span class="hljs-params">(UserService userService)</span> </span>{
        <span class="hljs-keyword">this</span>.userService = userService;
    }

    <span class="hljs-comment">/**
     * Handles user signup requests.
     * Endpoint: POST /api/users/signup
     * 
     * <span class="hljs-doctag">@param</span> key Unique key for the new user
     * <span class="hljs-doctag">@return</span> Created User object
     */</span>
    <span class="hljs-meta">@PostMapping("/signup")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> User <span class="hljs-title">signup</span><span class="hljs-params">(<span class="hljs-meta">@RequestBody</span> String key)</span> </span>{
        <span class="hljs-keyword">return</span> userService.signup(key);  <span class="hljs-comment">// Calls the signup method in UserService to create a new user</span>
    }

    <span class="hljs-comment">/**
     * Handles assigning a role to the logged-in user.
     * Endpoint: POST /api/users/assign-role
     * 
     * <span class="hljs-doctag">@param</span> request HTTP request, used to retrieve the current user
     * <span class="hljs-doctag">@param</span> role Role to be assigned to the current user
     */</span>
    <span class="hljs-meta">@PostMapping("/assign-role")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">assignRole</span><span class="hljs-params">(HttpServletRequest request, <span class="hljs-meta">@RequestBody</span> String role)</span> </span>{
        <span class="hljs-comment">// Retrieves the current user from the request attributes</span>
        User currentUser = (User) request.getAttribute(<span class="hljs-string">"user"</span>);

        <span class="hljs-comment">// Throws an exception if the user is not logged in</span>
        <span class="hljs-keyword">if</span> (currentUser == <span class="hljs-keyword">null</span>) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UnauthorizedException(<span class="hljs-string">"Not logged in"</span>);
        }

        <span class="hljs-comment">// Assigns the specified role to the current user</span>
        userService.assignRole(currentUser, role);
    }
}
</code></pre>
<h4 id="heading-creating-rbac-abac-and-rebac-policy-enforcement-point"><strong>Creating RBAC, ABAC, and ReBAC Policy Enforcement Point</strong></h4>
<p>In the code below, the <strong>ProductService</strong> class manages CRUD operations for products and reviews, handling permissions and roles via the Permit API.</p>
<p>Each operation includes user <code>authorization</code> checks, with appropriate exception handling for Permit API errors and resource not found scenarios.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.boostmytool.store.service;

<span class="hljs-keyword">import</span> com.boostmytool.store.exception.ResourceNotFoundException;
<span class="hljs-keyword">import</span> com.boostmytool.store.model.Product;
<span class="hljs-keyword">import</span> com.boostmytool.store.model.Review;
<span class="hljs-keyword">import</span> io.permit.sdk.Permit;
<span class="hljs-keyword">import</span> io.permit.sdk.api.PermitApiError;
<span class="hljs-keyword">import</span> io.permit.sdk.api.PermitContextError;
<span class="hljs-keyword">import</span> io.permit.sdk.enforcement.Resource;
<span class="hljs-keyword">import</span> io.permit.sdk.enforcement.User;
<span class="hljs-keyword">import</span> io.permit.sdk.openapi.models.RelationshipTupleCreate;
<span class="hljs-keyword">import</span> io.permit.sdk.openapi.models.ResourceInstanceCreate;
<span class="hljs-keyword">import</span> io.permit.sdk.openapi.models.RoleAssignmentCreate;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Service;

<span class="hljs-keyword">import</span> java.io.IOException;
<span class="hljs-keyword">import</span> java.util.ArrayList;
<span class="hljs-keyword">import</span> java.util.HashMap;
<span class="hljs-keyword">import</span> java.util.List;
<span class="hljs-keyword">import</span> java.util.concurrent.atomic.AtomicInteger;

<span class="hljs-meta">@Service</span>  <span class="hljs-comment">// Marks this class as a Spring service</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ProductService</span> </span>{

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> List&lt;Product&gt; products = <span class="hljs-keyword">new</span> ArrayList&lt;&gt;();  <span class="hljs-comment">// In-memory list to store products</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> AtomicInteger productIdCounter = <span class="hljs-keyword">new</span> AtomicInteger();  <span class="hljs-comment">// Counter to generate unique product IDs</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> AtomicInteger reviewIdCounter = <span class="hljs-keyword">new</span> AtomicInteger();   <span class="hljs-comment">// Counter to generate unique review IDs</span>

    <span class="hljs-comment">// Builders for Permit resource instances (product and review)</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> Resource.Builder productResourceBuilder = <span class="hljs-keyword">new</span> Resource.Builder(<span class="hljs-string">"product"</span>);
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> Resource.Builder reviewResourceBuilder = <span class="hljs-keyword">new</span> Resource.Builder(<span class="hljs-string">"review"</span>);

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> UserService userService;  <span class="hljs-comment">// Service for handling user-related operations</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> Permit permit;  <span class="hljs-comment">// Permit SDK instance for handling authorization and resource management</span>

    <span class="hljs-comment">// Constructor for injecting dependencies</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ProductService</span><span class="hljs-params">(UserService userService, Permit permit)</span> </span>{
        <span class="hljs-keyword">this</span>.userService = userService;
        <span class="hljs-keyword">this</span>.permit = permit;
    }

    <span class="hljs-comment">// Method to authorize a user for a given action on a resource</span>
    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">authorize</span><span class="hljs-params">(User user, String action, Resource resource)</span> </span>{
        userService.authorize(user, action, resource);
    }

    <span class="hljs-comment">// Authorizes a user to perform an action on a specific product</span>
    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">authorize</span><span class="hljs-params">(User user, String action, Product product)</span> </span>{
        <span class="hljs-keyword">var</span> attributes = <span class="hljs-keyword">new</span> HashMap&lt;String, Object&gt;();
        attributes.put(<span class="hljs-string">"vendor"</span>, product.getVendor());  <span class="hljs-comment">// Add vendor attribute to the product</span>
        userService.authorize(user, action, productResourceBuilder.withKey(product.getId().toString()).withAttributes(attributes).build());
    }

    <span class="hljs-comment">// Authorizes a user to perform an action on a specific review</span>
    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">authorize</span><span class="hljs-params">(User user, String action, Review review)</span> </span>{
        <span class="hljs-keyword">var</span> attributes = <span class="hljs-keyword">new</span> HashMap&lt;String, Object&gt;();
        attributes.put(<span class="hljs-string">"customer"</span>, review.getCustomer());  <span class="hljs-comment">// Add customer attribute to the review</span>
        userService.authorize(user, action, reviewResourceBuilder.withKey(review.getId().toString()).withAttributes(attributes).build());
    }

    <span class="hljs-comment">// Retrieves a product by its ID, throws an exception if not found</span>
    <span class="hljs-function"><span class="hljs-keyword">private</span> Product <span class="hljs-title">getProductById</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id)</span> </span>{
        <span class="hljs-keyword">return</span> products.stream().filter(product -&gt; product.getId().equals(id))
                .findFirst().orElseThrow(() -&gt; <span class="hljs-keyword">new</span> ResourceNotFoundException(<span class="hljs-string">"Product with id "</span> + id + <span class="hljs-string">" not found"</span>));
    }

    <span class="hljs-comment">// Retrieves all products, checks if the user is authorized to "read" products</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;Product&gt; <span class="hljs-title">getAllProducts</span><span class="hljs-params">(User user)</span> </span>{
        authorize(user, <span class="hljs-string">"read"</span>, productResourceBuilder.build());  <span class="hljs-comment">// User must have "read" permission</span>
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> ArrayList&lt;&gt;(products);  <span class="hljs-comment">// Return a copy of the products list</span>
    }

    <span class="hljs-comment">// Retrieves a product by its ID, checks if the user is authorized to "read" the product</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Product <span class="hljs-title">getProduct</span><span class="hljs-params">(User user, <span class="hljs-keyword">int</span> id)</span> </span>{
        authorize(user, <span class="hljs-string">"read"</span>, productResourceBuilder.build());
        <span class="hljs-keyword">return</span> getProductById(id);
    }

    <span class="hljs-comment">// Adds a new product, authorizes the user and creates resource instances and role assignments in Permit</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Product <span class="hljs-title">addProduct</span><span class="hljs-params">(User user, String content)</span> </span>{
        authorize(user, <span class="hljs-string">"create"</span>, productResourceBuilder.build());  <span class="hljs-comment">// Check if user can create a product</span>
        Product product = <span class="hljs-keyword">new</span> Product(productIdCounter.incrementAndGet(), user.getKey(), content);  <span class="hljs-comment">// Create new product</span>

        <span class="hljs-keyword">try</span> {
            <span class="hljs-comment">// Create resource instance in Permit and assign "vendor" role to the user for this product</span>
            permit.api.resourceInstances.create(<span class="hljs-keyword">new</span> ResourceInstanceCreate(product.getId().toString(), <span class="hljs-string">"product"</span>).withTenant(<span class="hljs-string">"default"</span>));
            permit.api.roleAssignments.assign(<span class="hljs-keyword">new</span> RoleAssignmentCreate(<span class="hljs-string">"vendor"</span>, user.getKey()).withResourceInstance(<span class="hljs-string">"product:"</span> + product.getId()).withTenant(<span class="hljs-string">"default"</span>));
        } <span class="hljs-keyword">catch</span> (IOException | PermitApiError | PermitContextError e) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"Failed to create resource instance or role assignment: "</span> + e.getMessage());
        }

        products.add(product);  <span class="hljs-comment">// Add product to in-memory list</span>
        <span class="hljs-keyword">return</span> product;
    }

    <span class="hljs-comment">// Updates a product's content, checks if the user is authorized to "update" the product</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Product <span class="hljs-title">updateProduct</span><span class="hljs-params">(User user, <span class="hljs-keyword">int</span> id, String content)</span> </span>{
        Product product = getProductById(id);  <span class="hljs-comment">// Get the product by its ID</span>
        authorize(user, <span class="hljs-string">"update"</span>, product);  <span class="hljs-comment">// Check if user can update the product</span>
        product.setContent(content);  <span class="hljs-comment">// Update product content</span>
        <span class="hljs-keyword">return</span> product;
    }

    <span class="hljs-comment">// Deletes a product, checks if the user is authorized to "delete" the product</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deleteProduct</span><span class="hljs-params">(User user, <span class="hljs-keyword">int</span> id)</span> </span>{
        <span class="hljs-keyword">boolean</span> isDeleted = products.removeIf(product -&gt; {
            <span class="hljs-keyword">if</span> (product.getId().equals(id)) {
                authorize(user, <span class="hljs-string">"delete"</span>, product);  <span class="hljs-comment">// Check if user can delete the product</span>
                <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;
            } <span class="hljs-keyword">else</span> {
                <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;
            }
        });

        <span class="hljs-keyword">if</span> (!isDeleted) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ResourceNotFoundException(<span class="hljs-string">"Product with id "</span> + id + <span class="hljs-string">" not found"</span>);
        }

        <span class="hljs-keyword">try</span> {
            permit.api.resourceInstances.delete(<span class="hljs-string">"product:"</span> + id);  <span class="hljs-comment">// Remove product resource instance from Permit</span>
        } <span class="hljs-keyword">catch</span> (IOException | PermitApiError | PermitContextError e) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(e);
        }
    }

    <span class="hljs-comment">// Adds a review to a product, creates a resource instance and relationship in Permit</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Review <span class="hljs-title">addReview</span><span class="hljs-params">(User user, <span class="hljs-keyword">int</span> productId, String content)</span> </span>{
        authorize(user, <span class="hljs-string">"create"</span>, reviewResourceBuilder.build());  <span class="hljs-comment">// Check if user can create a review</span>
        Product product = getProductById(productId);  <span class="hljs-comment">// Get the product by its ID</span>
        Review review = <span class="hljs-keyword">new</span> Review(reviewIdCounter.incrementAndGet(), user.getKey(), content);  <span class="hljs-comment">// Create new review</span>

        <span class="hljs-keyword">try</span> {
            <span class="hljs-comment">// Create a resource instance for the review and set relationship with the product</span>
            permit.api.resourceInstances.create(<span class="hljs-keyword">new</span> ResourceInstanceCreate(review.getId().toString(), <span class="hljs-string">"review"</span>).withTenant(<span class="hljs-string">"default"</span>));
            permit.api.relationshipTuples.create(<span class="hljs-keyword">new</span> RelationshipTupleCreate(<span class="hljs-string">"product:"</span> + productId, <span class="hljs-string">"parent"</span>, <span class="hljs-string">"review:"</span> + review.getId()));
        } <span class="hljs-keyword">catch</span> (IOException | PermitApiError | PermitContextError e) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(e);
        }

        product.addReview(review);  <span class="hljs-comment">// Add the review to the product</span>
        <span class="hljs-keyword">return</span> review;
    }

    <span class="hljs-comment">// Updates a review's content, checks if the user is authorized to "update" the review</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Review <span class="hljs-title">updateReview</span><span class="hljs-params">(User user, <span class="hljs-keyword">int</span> productId, <span class="hljs-keyword">int</span> reviewId, String content)</span> </span>{
        Product product = getProductById(productId);  <span class="hljs-comment">// Get the product by its ID</span>
        Review review = product.getReviews().stream().filter(c -&gt; c.getId().equals(reviewId))
                .findFirst().orElseThrow(() -&gt; <span class="hljs-keyword">new</span> ResourceNotFoundException(<span class="hljs-string">"Review with id "</span> + reviewId + <span class="hljs-string">" not found"</span>));

        authorize(user, <span class="hljs-string">"update"</span>, review);  <span class="hljs-comment">// Check if user can update the review</span>
        review.setContent(content);  <span class="hljs-comment">// Update review content</span>
        <span class="hljs-keyword">return</span> review;
    }

    <span class="hljs-comment">// Deletes a review, checks if the user is authorized to "delete" the review</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deleteReview</span><span class="hljs-params">(User user, <span class="hljs-keyword">int</span> productId, <span class="hljs-keyword">int</span> reviewId)</span> </span>{
        Product product = getProductById(productId);  <span class="hljs-comment">// Get the product by its ID</span>
        <span class="hljs-keyword">boolean</span> isDeleted = product.getReviews().removeIf(review -&gt; {
            <span class="hljs-keyword">if</span> (review.getId().equals(reviewId)) {
                authorize(user, <span class="hljs-string">"delete"</span>, review);  <span class="hljs-comment">// Check if user can delete the review</span>
                <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;
            } <span class="hljs-keyword">else</span> {
                <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;
            }
        });

        <span class="hljs-keyword">if</span> (!isDeleted) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ResourceNotFoundException(<span class="hljs-string">"Review with id "</span> + reviewId + <span class="hljs-string">" not found"</span>);
        }

        <span class="hljs-keyword">try</span> {
            permit.api.resourceInstances.delete(<span class="hljs-string">"review:"</span> + reviewId);  <span class="hljs-comment">// Remove review resource instance from Permit</span>
        } <span class="hljs-keyword">catch</span> (IOException | PermitApiError | PermitContextError e) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(e);
        }
    }
}
</code></pre>
<p>Then in the code below, the <strong>ProductController</strong> class handles HTTP requests related to products and their reviews. It exposes endpoints for managing products (like <code>creating</code>, <code>updating</code>, <code>deleting</code>, and <code>retrieving</code>) and for managing product reviews.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.boostmytool.store.controllers;

<span class="hljs-keyword">import</span> com.boostmytool.store.model.Product;
<span class="hljs-keyword">import</span> com.boostmytool.store.model.Review;
<span class="hljs-keyword">import</span> com.boostmytool.store.service.ProductService;
<span class="hljs-keyword">import</span> io.permit.sdk.enforcement.User;
<span class="hljs-keyword">import</span> jakarta.servlet.http.HttpServletRequest;
<span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Autowired;
<span class="hljs-keyword">import</span> org.springframework.http.HttpStatus;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.*;

<span class="hljs-keyword">import</span> java.util.List;

<span class="hljs-meta">@RestController</span>  <span class="hljs-comment">// Indicates that this class is a Spring REST controller</span>
<span class="hljs-meta">@RequestMapping("/api/products")</span>  <span class="hljs-comment">// Base URL for all endpoints in this controller</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ProductController</span> </span>{

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> ProductService productService;  <span class="hljs-comment">// ProductService instance to handle product-related operations</span>

    <span class="hljs-meta">@Autowired</span>  <span class="hljs-comment">// Autowires ProductService bean automatically</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ProductController</span><span class="hljs-params">(ProductService productService)</span> </span>{
        <span class="hljs-keyword">this</span>.productService = productService;
    }

    <span class="hljs-comment">// GET request to retrieve all products</span>
    <span class="hljs-meta">@GetMapping</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;Product&gt; <span class="hljs-title">getAllProducts</span><span class="hljs-params">(HttpServletRequest request)</span> </span>{
        User currentUser = (User) request.getAttribute(<span class="hljs-string">"user"</span>);  <span class="hljs-comment">// Gets the authenticated user from the request</span>
        <span class="hljs-keyword">return</span> productService.getAllProducts(currentUser);  <span class="hljs-comment">// Calls ProductService to get all products for the user</span>
    }

    <span class="hljs-comment">// GET request to retrieve a product by its ID</span>
    <span class="hljs-meta">@GetMapping("/{id}")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Product <span class="hljs-title">getProductById</span><span class="hljs-params">(HttpServletRequest request, <span class="hljs-meta">@PathVariable("id")</span> <span class="hljs-keyword">int</span> id)</span> </span>{
        User currentUser = (User) request.getAttribute(<span class="hljs-string">"user"</span>);  <span class="hljs-comment">// Gets the authenticated user from the request</span>
        <span class="hljs-keyword">return</span> productService.getProduct(currentUser, id);  <span class="hljs-comment">// Calls ProductService to get the product by ID for the user</span>
    }

    <span class="hljs-comment">// POST request to add a new product</span>
    <span class="hljs-meta">@PostMapping</span>
    <span class="hljs-meta">@ResponseStatus(HttpStatus.CREATED)</span>  <span class="hljs-comment">// Sets the response status to 201 (Created)</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Product <span class="hljs-title">addProduct</span><span class="hljs-params">(HttpServletRequest request, <span class="hljs-meta">@RequestBody</span> String content)</span> </span>{
        User currentUser = (User) request.getAttribute(<span class="hljs-string">"user"</span>);  <span class="hljs-comment">// Gets the authenticated user from the request</span>
        <span class="hljs-keyword">return</span> productService.addProduct(currentUser, content);  <span class="hljs-comment">// Calls ProductService to add a new product</span>
    }

    <span class="hljs-comment">// PUT request to update an existing product by its ID</span>
    <span class="hljs-meta">@PutMapping("/{id}")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Product <span class="hljs-title">updateProduct</span><span class="hljs-params">(HttpServletRequest request, <span class="hljs-meta">@PathVariable("id")</span> <span class="hljs-keyword">int</span> id, <span class="hljs-meta">@RequestBody</span> String content)</span> </span>{
        User currentUser = (User) request.getAttribute(<span class="hljs-string">"user"</span>);  <span class="hljs-comment">// Gets the authenticated user from the request</span>
        <span class="hljs-keyword">return</span> productService.updateProduct(currentUser, id, content);  <span class="hljs-comment">// Calls ProductService to update the product by ID</span>
    }

    <span class="hljs-comment">// DELETE request to delete a product by its ID</span>
    <span class="hljs-meta">@DeleteMapping("/{id}")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">deleteProduct</span><span class="hljs-params">(HttpServletRequest request, <span class="hljs-meta">@PathVariable("id")</span> <span class="hljs-keyword">int</span> id)</span> </span>{
        User currentUser = (User) request.getAttribute(<span class="hljs-string">"user"</span>);  <span class="hljs-comment">// Gets the authenticated user from the request</span>
        productService.deleteProduct(currentUser, id);  <span class="hljs-comment">// Calls ProductService to delete the product by ID</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Deleted product with id "</span> + id;  <span class="hljs-comment">// Returns a success message after deletion</span>
    }

    <span class="hljs-comment">// POST request to add a new review to a product by product ID</span>
    <span class="hljs-meta">@PostMapping("/{id}/review")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Review <span class="hljs-title">addReview</span><span class="hljs-params">(HttpServletRequest request, <span class="hljs-meta">@PathVariable("id")</span> <span class="hljs-keyword">int</span> id, <span class="hljs-meta">@RequestBody</span> String content)</span> </span>{
        User currentUser = (User) request.getAttribute(<span class="hljs-string">"user"</span>);  <span class="hljs-comment">// Gets the authenticated user from the request</span>
        <span class="hljs-keyword">return</span> productService.addReview(currentUser, id, content);  <span class="hljs-comment">// Calls ProductService to add a review to the product</span>
    }

    <span class="hljs-comment">// PUT request to update an existing review by product and review ID</span>
    <span class="hljs-meta">@PutMapping("/{id}/review/{reviewId}")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Review <span class="hljs-title">updateReview</span><span class="hljs-params">(HttpServletRequest request, <span class="hljs-meta">@PathVariable("id")</span> <span class="hljs-keyword">int</span> id, <span class="hljs-meta">@PathVariable("reviewId")</span> <span class="hljs-keyword">int</span> reviewId, <span class="hljs-meta">@RequestBody</span> String content)</span> </span>{
        User currentUser = (User) request.getAttribute(<span class="hljs-string">"user"</span>);  <span class="hljs-comment">// Gets the authenticated user from the request</span>
        <span class="hljs-keyword">return</span> productService.updateReview(currentUser, id, reviewId, content);  <span class="hljs-comment">// Calls ProductService to update the review</span>
    }

    <span class="hljs-comment">// DELETE request to delete a review by product and review ID</span>
    <span class="hljs-meta">@DeleteMapping("/{id}/review/{reviewId}")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">deleteReview</span><span class="hljs-params">(HttpServletRequest request, <span class="hljs-meta">@PathVariable("id")</span> <span class="hljs-keyword">int</span> id, <span class="hljs-meta">@PathVariable("reviewId")</span> <span class="hljs-keyword">int</span> reviewId)</span> </span>{
        User currentUser = (User) request.getAttribute(<span class="hljs-string">"user"</span>);  <span class="hljs-comment">// Gets the authenticated user from the request</span>
        productService.deleteReview(currentUser, id, reviewId);  <span class="hljs-comment">// Calls ProductService to delete the review</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Deleted review with id "</span> + reviewId + <span class="hljs-string">" from product "</span> + id;  <span class="hljs-comment">// Returns a success message after deletion</span>
    }
}
</code></pre>
<h3 id="heading-step-2-get-your-environment-api-key"><strong>Step 2: Get your Environment API Key</strong></h3>
<p>In the UI Dashboard, copy the Environment <code>API Key</code> of the active environment.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729498343969/2bbbd4a0-512f-4b46-a82a-ca41ecb67a4c.png" alt="Permit.io - copy env key" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Then add the env <code>API key</code> and <code>PDP URL</code> in the <code>application.yaml</code> file.</p>
<pre><code class="lang-plaintext">permit:
  pdpUrl: 'http://localhost:7766'
  apiKey: "Your Permit environment API Key"
</code></pre>
<h3 id="heading-step-3-deploy-policy-decision-point-pdp"><strong>Step 3: Deploy Policy Decision Point (PDP)</strong></h3>
<p>The Policy Decision Point (PDP) is deployed in your VPC and is in charge of evaluating your authorization requests. The PDP will ensure zero latency, great performance, high availability, and improved security.</p>
<p>Use the command below to pull the <a target="_blank" href="http://Permit.io">Permit.io</a> PDP container from <code>Docker</code> Hub.</p>
<pre><code class="lang-dockerfile">docker pull permitio/pdp-v2:latest
</code></pre>
<p>Then run the container.</p>
<pre><code class="lang-dockerfile">docker <span class="hljs-keyword">run</span><span class="bash"> -it -p 7766:7000 --env PDP_DEBUG=True --env PDP_API_KEY=&lt;YOUR_API_KEY&gt; permitio/pdp-v2:latest</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729515246656/6bed08e3-6109-4643-a724-f55641d7c974.png" alt="Permit.io - local testing" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-step-4-running-the-app"><strong>Step 4: Running the App</strong></h3>
<p>You can run the application using the following <code>Gradle</code> command:</p>
<pre><code class="lang-dockerfile">./gradlew bootRun
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729515837209/41556843-b8d5-4433-a2f3-93371562d27d.png" alt="Permit.io - how to run the app in local" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h4 id="heading-viewing-and-creating-products"><strong>Viewing and Creating Products</strong></h4>
<p>Let’s now interact with the application endpoints using <a target="_blank" href="https://reqbin.com/curl">REQBIN</a>.</p>
<p>First, create a new user using the <code>/api/users/signup</code> endpoint.</p>
<pre><code class="lang-dockerfile">curl -X POST <span class="hljs-string">"http://localhost:8080/api/users/signup"</span> -H <span class="hljs-string">"Content-Type: application/json"</span> -d <span class="hljs-string">'johndoe'</span>
</code></pre>
<p>You should be able to view the user in your Permit project, under Directory &gt; All Tenants.</p>
<p>Initially, the user has no roles, so it cannot do much. For example, trying to list the products will result in a 403 Forbidden response, as shown below. The 403 error code means the user doesn’t have permissions to access the requested resource, which is products in this case. You can learn more about <a target="_blank" href="https://www.permit.io/blog/401-vs-403-error-whats-the-difference">the difference between 401 and 403 error codes here</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729498632123/aaf26b76-a89f-4e6b-9324-85d082b8061d.png" alt="Permit.io - endpoints" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>For the user to view a list of products, assign them a viewer role using the command below:</p>
<pre><code class="lang-dockerfile">curl -X POST <span class="hljs-string">"http://localhost:8080/api/users/assign-role"</span> \
-H <span class="hljs-string">"Authorization: Bearer johndoe"</span> \
-H <span class="hljs-string">"Content-Type: application/json"</span> \
-d <span class="hljs-string">'viewer'</span>
</code></pre>
<p>You should see that user <code>johndoe</code> was assigned role viewer, as shown below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729498710784/ebd789fd-ec52-4146-bb94-6f300edb9d7e.png" alt="Permit.io - users" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Since a viewer can create a product, use the command below to create a product with user <code>johndoe</code>.</p>
<pre><code class="lang-dockerfile">curl -X POST <span class="hljs-string">"http://localhost:8080/api/products"</span> -H <span class="hljs-string">"Authorization: Bearer johndoe"</span> -H <span class="hljs-string">"Content-Type: application/json"</span> -d <span class="hljs-string">'MacBook'</span>
</code></pre>
<p>You should see that a new product is created with ID 1 and that the user <code>johndoe</code> has been added as the vendor.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729498758160/c14169f0-d720-465e-9bc1-f7096e6da31a.png" alt="Permit.io - API end points " class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h4 id="heading-adding-reviews-to-products"><strong>Adding Reviews To Products</strong></h4>
<p>To add reviews to products, create another user called <code>jane</code>.</p>
<pre><code class="lang-dockerfile">curl -X POST <span class="hljs-string">"http://localhost:8080/api/users/signup"</span> -H <span class="hljs-string">"Content-Type: application/json"</span> -d <span class="hljs-string">'jane'</span>
</code></pre>
<p>For the user to add a review to products, assign them a <code>viewer</code> role using the command below:</p>
<pre><code class="lang-dockerfile">curl -X POST <span class="hljs-string">"http://localhost:8080/api/users/assign-role"</span> \
-H <span class="hljs-string">"Authorization: Bearer jane"</span> \
-H <span class="hljs-string">"Content-Type: application/json"</span> \
-d <span class="hljs-string">'viewer'</span>
</code></pre>
<p>Then you can add a review to the product added by <code>johndoe</code> using the command below:</p>
<pre><code class="lang-dockerfile">curl -X POST <span class="hljs-string">"http://localhost:8080/api/products/1/review"</span> -H <span class="hljs-string">"Authorization: Bearer jane"</span> -H <span class="hljs-string">"Content-Type: application/json"</span> -d <span class="hljs-string">'The product was in good quality'</span>
</code></pre>
<p>Congratulations! You’ve completed the project for this tutorial.</p>
<h2 id="heading-next-steps">Next Steps</h2>
<p>Now that you've learned how to implement fine-grained authorization in your Java and Spring Boot applications using <a target="_blank" href="http://Permit.io">Permit.io</a>, you might want to explore further.</p>
<p>Here are some valuable resources:</p>
<ul>
<li><p><a target="_blank" href="https://docs.permit.io/">Permit.io docs</a></p>
</li>
<li><p><a target="_blank" href="https://www.permit.io/blog/rbac-vs-abac">RBAC VS ABAC: Choosing the Right Authorization Policy Model</a></p>
</li>
</ul>
<h3 id="heading-before-we-end">Before We End</h3>
<p>I hope you found this tutorial insightful.</p>
<p>Here are some of my other recent blog posts that you might enjoy:</p>
<ul>
<li><p><a target="_blank" href="https://www.freecodecamp.org/news/learn-react-key-concepts/">Learn React – A Guide to the Key Concepts</a></p>
</li>
<li><p><a target="_blank" href="https://www.devtoolsacademy.com/blog/neon-vs-supabase"><strong>Neon Postgres vs Supabase</strong></a></p>
</li>
<li><p><a target="_blank" href="https://www.freecodecamp.org/news/nextjs-clerk-neon-fullstack-development/">Full Stack Development with Next.js, Clerk, and Neon Postgres</a></p>
</li>
</ul>
<p>For more tutorials on amazing developer tools, be sure to check out my blog <a target="_blank" href="https://www.devtoolsacademy.com/">DTA</a>.</p>
<p>Follow me on <a target="_blank" href="https://x.com/TheAnkurTyagi">Twitter</a> to get live updates on my other projects.</p>
<p>Happy coding.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Implement JSON Web Tokens (JWTs) in PHP – PHP Authentication Tutorial ]]>
                </title>
                <description>
                    <![CDATA[ In this guide, we'll explore the process of creating JSON Web Tokens (JWTs) from scratch in PHP, which is a superior and more secure authentication scheme.  By implementing this advanced approach, you'll have a robust and highly secure authentication... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/php-jwt-authentication-implementation/</link>
                <guid isPermaLink="false">66bae6f4e2f22beb3be3a538</guid>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ authorization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ handbook ]]>
                    </category>
                
                    <category>
                        <![CDATA[ PHP ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oghenekparobo Stephen ]]>
                </dc:creator>
                <pubDate>Wed, 24 Apr 2024 18:41:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/04/How-to-Implement-JSON-Web-Tokens-in-PHP-Cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this guide, we'll explore the process of creating JSON Web Tokens (JWTs) from scratch in PHP, which is a superior and more secure authentication scheme. </p>
<p>By implementing this advanced approach, you'll have a robust and highly secure authentication mechanism that significantly enhances data protection and user authentication.</p>
<h2 id="heading-table-of-contents">Table Of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-what-are-json-web-tokens-jwts">What Are JSON Web Tokens (JWTs)?</a></li>
<li><a class="post-section-overview" href="#heading-getting-started">Getting Started</a></li>
<li><a class="post-section-overview" href="#heading-sending-our-requests">Sending Our Requests</a></li>
<li><a class="post-section-overview" href="#heading-testing-database-connection">Testing Database Connection</a></li>
<li><a class="post-section-overview" href="#heading-registering-users">Registering Users</a></li>
<li><a class="post-section-overview" href="#heading-setting-up-the-jwt-class">Setting up the JWT Class</a></li>
<li><a class="post-section-overview" href="#heading-the-encode-method">The Encode Method</a></li>
<li><a class="post-section-overview" href="#heading-the-login-endpoint">The Login Endpoint</a></li>
<li><a class="post-section-overview" href="#heading-protected-resources-and-decoding-json-web-tokens">Protected Resources And Decoding JSON Web Tokens</a></li>
<li><a class="post-section-overview" href="#heading-what-happens-now">What Happens Now?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-the-decode-method-in-our-jwt-class">How to Set Up The Decode Method In Our JWT Class</a></li>
<li><a class="post-section-overview" href="#heading-protected-resources">Protected Resources</a></li>
<li><a class="post-section-overview" href="#heading-checking-the-headers-for-the-correct-authorization-scheme">Checking The Headers For The Correct Authorization Scheme</a></li>
<li><a class="post-section-overview" href="#heading-creating-instances-in-the-api-entry-point">Creating Instances In The API Entry Point</a></li>
<li><a class="post-section-overview" href="#heading-suggestions">Suggestions</a></li>
<li><a class="post-section-overview" href="#heading-how-to-implement-token-expiration">How to Implement Token Expiration</a></li>
<li><a class="post-section-overview" href="#heading-updated-folder-structure">Updated Folder Structure</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ul>
<h2 id="heading-what-are-json-web-tokens-jwts">What Are JSON Web Tokens (JWTs)?</h2>
<p>A JSON Web Token is a string composed of three parts, each joined by a period (.), and then base64url encoded.</p>
<p>Here are the three parts of a JWT:</p>
<p><strong>Header</strong>: A header consists of metadata about the token, such as the token type and the algorithm used.</p>
<pre><code class="lang-php"> $header = json_encode([
            <span class="hljs-string">"alg"</span> =&gt; <span class="hljs-string">"HS256"</span>,
            <span class="hljs-string">"typ"</span> =&gt; <span class="hljs-string">"JWT"</span>
        ]);

        $header = <span class="hljs-keyword">$this</span>-&gt;base64urlEncode($header);
</code></pre>
<p><strong>Payload:</strong> Within the JWT structure, the payload encapsulates specific indices referred to as claims, housing user data that is encoded using base64url.</p>
<pre><code class="lang-php">$payload = [
    <span class="hljs-string">"id"</span> =&gt; $user[<span class="hljs-string">'id'</span>],
    <span class="hljs-string">"name"</span> =&gt; $user[<span class="hljs-string">"name"</span>]
];

  $payload = <span class="hljs-keyword">$this</span>-&gt;base64urlEncode($payload);
</code></pre>
<p><strong>Signature:</strong> This is generated by creating a hash of the header and payload, combined with a secret key typically generated as either 256 bits or 32 bytes. By convention, the secret key matches the size of the hash output.</p>
<p>We will use the link below to generate a secret key we need for this project:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://generate-random.org/encryption-key-generator?source=post_page-----ebf5693b931a--------------------------------">https://generate-random.org/encryption-key-generator?source=post_page-----ebf5693b931a--------------------------------</a></div>
<pre><code class="lang-php"> $signature = hash_hmac(<span class="hljs-string">"sha256"</span>, $header . <span class="hljs-string">"."</span> . $payload, $secret_key, <span class="hljs-literal">true</span>);
 $signature = <span class="hljs-keyword">$this</span>-&gt;base64urlEncode($signature);
</code></pre>
<p>A JSON Web Token is simply a combination of the header, payload, and signature, where each component is concatenated together with periods (“.”) in between:</p>
<pre><code class="lang-bash"><span class="hljs-variable">$header</span> . <span class="hljs-string">"."</span> . <span class="hljs-variable">$payload</span> . <span class="hljs-string">"."</span> . <span class="hljs-variable">$signature</span>;
</code></pre>
<h2 id="heading-getting-started">Getting Started</h2>
<p>To kickstart this project, please download the project starter from the following link: <a target="_blank" href="https://github.com/Oghenekparobo/php_auth_jwt_tut">PHP Authentication with JWT Tutorial</a>. </p>
<p>Once downloaded, carefully review the <strong>README.md</strong> file included in the repository for comprehensive information regarding pre-installed packages. The file contains essential details such as notes on security and best practices. Taking the time to thoroughly read through the <strong>README</strong> will ensure a smooth setup and understanding of the project.</p>
<p>To initiate the setup of the project, utilize Git by executing the following command:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/Oghenekparobo/php_auth_jwt_tut.git
</code></pre>
<p>This command will clone the project repository to your local system, allowing you to proceed with the installation and configuration process.</p>
<p>After cloning the project from GitHub, your project structure should align with the following layout:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/1_ZQ1u8lazV-ID3fJ9bFKUMA.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>project structure on VS Code</em></p>
<p>project_root/
│
├── api/
│   ├── .htaccess
│   ├── index.php
│   └── (other PHP files)
│
├── vendor/
│   ├── (Composer dependencies)
│   └── ...
│
├── .env
├── README.md
└── (other project files)</p>
<p><strong>In this structure:</strong></p>
<ul>
<li>The <code>api/</code> directory contains PHP files responsible for handling API requests and responses. It includes an <code>.htaccess</code> file for URL rewriting and an <code>index.php</code> file, along with other PHP files for specific functionalities.</li>
<li>The <code>vendor/</code> directory contains Composer dependencies installed for the project. These dependencies are managed by Composer and should not be modified directly.</li>
<li>The <code>.env</code> file contains environment variables necessary for configuring the application environment, such as database credentials and API keys.</li>
<li>The <code>README.md</code> file provides essential information about the project, including setup instructions, usage guidelines, and any other relevant details.</li>
</ul>
<p>Ensure that you maintain this structure and follow any instructions provided in the <strong>README</strong> file to set up and run the project successfully.</p>
<h2 id="heading-sending-our-requests">Sending Our Requests</h2>
<p>When referring to our project, the URL would typically be structured as follows: <code>http://localhost/php_auth_jwt_tut/api</code>. However, depending on the project's name, this URL might vary accordingly. Nonetheless, the base URL remains consistent: <code>[http://localhost/php_auth_jwt_tut/api](http://localhost/php_auth_jwt_tut/api.)</code><a target="_blank" href="http://localhost/php_auth_jwt_tut/api.">.</a></p>
<p>Thanks to our implementation of URL rewriting in the <code>.htaccess</code> file, additional prefixes such as <code>index.php</code> or <code>.php</code> are unnecessary when accessing our URLs. We've meticulously configured our server settings to ensure seamless navigation without these prefixes.</p>
<p>In simpler terms, accessing our project’s API endpoints can be done directly from the base URL: <code>http://localhost/php_auth_jwt_tut/api</code>. This streamlined approach enhances user experience and eliminates unnecessary complexity for this project.</p>
<p>To make testing our project’s API endpoints easier, we can use the <strong>index.php</strong> file located in the <strong>api</strong> folder. This file acts as the starting point for our application and contains all the necessary setups.</p>
<p>Firstly, we’ll simply print out any desired output within the <strong>index.php</strong> file. This helps us confirm that our endpoint is working correctly. Then, we'll test the endpoint by accessing the URL: <code>[http://localhost/php_auth_jwt_tut/api](http://localhost/php_auth_jwt_tut/api.)</code><a target="_blank" href="http://localhost/php_auth_jwt_tut/api.">.</a></p>
<p>Additionally, we’ll set up our database connection to ensure smooth communication between our API endpoints and the database. All the required configurations are included within the <a target="_blank" href="https://github.com/Oghenekparobo/php_auth_jwt_tut/blob/main/api/bootstrap.php"><strong>bootstrap.php</strong></a> file for convenience. By importing this file into our <a target="_blank" href="https://github.com/Oghenekparobo/php_auth_jwt_tut/blob/main/api/index.php"><strong>index.php</strong></a>, managing configurations and imports becomes simpler.</p>
<p>Furthermore, it’s important to note that we’ll be enforcing strict typing throughout our codebase. This means that we’ll specify the types of data our variables and functions can hold or return. This helps maintain consistency and reduces the chances of errors in our code.</p>
<h2 id="heading-testing-database-connection">Testing Database Connection</h2>
<p>Before proceeding with the steps outlined in this section, it is imperative to thoroughly review the <strong>README</strong> file of this project. This will provide you with comprehensive instructions on how to set up your database properly. In the root of the project, you will find a file named <a target="_blank" href="https://github.com/Oghenekparobo/php_auth_jwt_tut/blob/main/college.sql"><strong>college.sql</strong></a>, which contains the necessary tables for your database. Simply follow the instructions provided in the <strong>README</strong> file to import and configure the database accordingly.</p>
<p>In the <strong>src</strong> folder of our project, we find essential classes and gateways, including the necessary database connections for our project. The file responsible for this is <strong>database.php</strong>, already configured to establish a PDO database connection.</p>
<p>Note: Before use, ensure to adjust or configure the variables in the <strong>.env</strong> environment file to match your database credentials.</p>
<p><strong>.env file</strong>:</p>
<pre><code class="lang-env">DB_HOST= 'db_host'
DB_NAME = 'db_name'
DB_USER = 'db_user'
DB_PASS = 'db_password'
SECRET_KEY = "secret_key"
</code></pre>
<p><strong>bootstrap.php</strong>:</p>
<pre><code class="lang-php"><span class="hljs-keyword">require</span> dirname(<span class="hljs-keyword">__DIR__</span>)  . <span class="hljs-string">'/vendor/autoload.php'</span>;

set_error_handler(<span class="hljs-string">'ErrorHandler::handleError'</span>);
set_exception_handler(<span class="hljs-string">'ErrorHandler::handleException'</span>);

$dotenv = Dotenv\Dotenv::createImmutable(dirname(<span class="hljs-keyword">__DIR__</span>));
$dotenv-&gt;load();

header(<span class="hljs-string">"Content-type: application/json; charset=UTF-8"</span>);


$database = <span class="hljs-keyword">new</span> Database(
    $_ENV[<span class="hljs-string">"DB_HOST"</span>],
    $_ENV[<span class="hljs-string">"DB_NAME"</span>],
    $_ENV[<span class="hljs-string">"DB_USER"</span>],
    $_ENV[<span class="hljs-string">"DB_PASS"</span>]
);
</code></pre>
<p>The code prepares our application by doing a few key things. First, it loads the necessary files to handle errors and exceptions smoothly. Then, it grabs environment variables from a special file (<strong>.env</strong>) where we store important settings like database information. After that, it tells the application to send back data in a specific format (JSON). Finally, it sets up a connection to the database using the information from the <strong>.env</strong> file. This setup ensures our application runs smoothly and securely.</p>
<p><strong>database.php</strong>:</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Database</span>
</span>{
    <span class="hljs-keyword">private</span> ?PDO $conn = <span class="hljs-literal">null</span>;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">string</span> $host,
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">string</span> $name,
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">string</span> $user,
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">string</span> $password
    </span>) </span>{
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getConnection</span>(<span class="hljs-params"></span>): ?<span class="hljs-title">PDO</span>
    </span>{
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">if</span> (<span class="hljs-keyword">$this</span>-&gt;conn === <span class="hljs-literal">null</span>) {
                <span class="hljs-keyword">$this</span>-&gt;conn = <span class="hljs-keyword">new</span> PDO(<span class="hljs-string">"mysql:host=<span class="hljs-subst">$this</span>-&gt;host;dbname=<span class="hljs-subst">{$this-&gt;name}</span>"</span>, <span class="hljs-keyword">$this</span>-&gt;user, <span class="hljs-keyword">$this</span>-&gt;password);
                <span class="hljs-keyword">$this</span>-&gt;conn-&gt;setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
                <span class="hljs-keyword">$this</span>-&gt;conn-&gt;setAttribute(PDO::ATTR_EMULATE_PREPARES, <span class="hljs-literal">false</span>);
                <span class="hljs-keyword">$this</span>-&gt;conn-&gt;setAttribute(PDO::ATTR_STRINGIFY_FETCHES, <span class="hljs-literal">false</span>);
            }

            <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;conn;
        } <span class="hljs-keyword">catch</span> (PDOException $e) {
            <span class="hljs-keyword">echo</span> <span class="hljs-string">"Connection failed: "</span> . $e-&gt;getMessage();
            <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
        }
    }
}
</code></pre>
<p>Include an echo statement to indicate a successful database connection before returning the <code>$this-&gt;conn</code> object. This helps to verify the connection status and ensure smooth operation of the application. For instance:</p>
<pre><code class="lang-php"><span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">$this</span>-&gt;conn === <span class="hljs-literal">null</span>) {
        <span class="hljs-keyword">$this</span>-&gt;conn = <span class="hljs-keyword">new</span> PDO(<span class="hljs-string">"mysql:host=<span class="hljs-subst">$this</span>-&gt;host;dbname=<span class="hljs-subst">{$this-&gt;name}</span>"</span>, <span class="hljs-keyword">$this</span>-&gt;user, <span class="hljs-keyword">$this</span>-&gt;password);
        <span class="hljs-keyword">$this</span>-&gt;conn-&gt;setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        <span class="hljs-keyword">$this</span>-&gt;conn-&gt;setAttribute(PDO::ATTR_EMULATE_PREPARES, <span class="hljs-literal">false</span>);
        <span class="hljs-keyword">$this</span>-&gt;conn-&gt;setAttribute(PDO::ATTR_STRINGIFY_FETCHES, <span class="hljs-literal">false</span>);

        <span class="hljs-comment">// Echo message indicating successful database connection</span>
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"Database connected successfully."</span>;
    }

    <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;conn;
} <span class="hljs-keyword">catch</span> (PDOException $e) {
    <span class="hljs-keyword">echo</span> <span class="hljs-string">"Connection failed: "</span> . $e-&gt;getMessage();
    <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
}
</code></pre>
<p>Proceed to the <strong>index.php</strong> file to invoke the <code>getConnection</code> function and verify the application's functionality. It's important to note that we've initialized our <code>Database</code> class in our bootstrap PHP file, ensuring seamless integration and operation.</p>
<p>Invoking the <code>getConnection</code> function in the <strong>index.php</strong> file should look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/1_YrpE0hGl-qf8QB8pChAFdA.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>index.php file</em></p>
<p>Upon successfully implementing the database connection and firing our request, you can expect the following response:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/1_hnCfjp2hp1Gzf2gkuey_nA.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>database connected successfully</em></p>
<p><strong>Note</strong>: Make sure you clear the echo after we are done.</p>
<h2 id="heading-registering-users">Registering Users</h2>
<p>To efficiently manage user data, we will implement a minimal frontend solution by creating a new file named <a target="_blank" href="https://github.com/Oghenekparobo/php_auth_jwt_tut/blob/main/register.php"><strong>register.php</strong></a> in the root directory of our project. Additionally, we will introduce a stylesheet named <a target="_blank" href="https://github.com/Oghenekparobo/php_auth_jwt_tut/blob/main/style.css"><strong>style.css</strong></a> to enhance the visual presentation of the registration page. </p>
<p>We will establish a connection to our database, facilitating the seamless addition of users to the user table within our college database. Upon successful user registration, a confirmation message will be echoed to affirm the addition of the user to the database.</p>
<p><strong>register.php</strong>:</p>
<pre><code class="lang-php"><span class="hljs-keyword">require</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">"/vendor/autoload.php"</span>;

<span class="hljs-keyword">if</span> ($_SERVER[<span class="hljs-string">"REQUEST_METHOD"</span>] === <span class="hljs-string">"POST"</span>) {

    $dotenv = Dotenv\Dotenv::createImmutable(<span class="hljs-keyword">__DIR__</span>);
    $dotenv-&gt;load();

    $database = <span class="hljs-keyword">new</span> Database(
        $_ENV[<span class="hljs-string">"DB_HOST"</span>],
        $_ENV[<span class="hljs-string">"DB_NAME"</span>],
        $_ENV[<span class="hljs-string">"DB_USER"</span>],
        $_ENV[<span class="hljs-string">"DB_PASS"</span>]
    );

    $conn = $database-&gt;getConnection();

    $sql = <span class="hljs-string">"INSERT INTO user (name, username, password_hash)
            VALUES (:name, :username, :password_hash)"</span>;

    $stmt = $conn-&gt;prepare($sql);

    $password_hash = password_hash($_POST[<span class="hljs-string">"password"</span>], PASSWORD_DEFAULT);


    $stmt-&gt;bindValue(<span class="hljs-string">":name"</span>, $_POST[<span class="hljs-string">"name"</span>], PDO::PARAM_STR);
    $stmt-&gt;bindValue(<span class="hljs-string">":username"</span>, $_POST[<span class="hljs-string">"username"</span>], PDO::PARAM_STR);
    $stmt-&gt;bindValue(<span class="hljs-string">":password_hash"</span>, $password_hash, PDO::PARAM_STR);


    $stmt-&gt;execute();

    <span class="hljs-keyword">echo</span> <span class="hljs-string">"Thank you for registering."</span>;
    <span class="hljs-keyword">exit</span>;
}

<span class="hljs-meta">?&gt;</span>
&lt;!DOCTYPE html&gt;
&lt;html lang=<span class="hljs-string">"en"</span>&gt;

&lt;head&gt;
    &lt;meta charset=<span class="hljs-string">"UTF-8"</span>&gt;
    &lt;meta name=<span class="hljs-string">"viewport"</span> content=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;
    &lt;title&gt;User Registration&lt;/title&gt;
    &lt;link rel=<span class="hljs-string">"stylesheet"</span> href=<span class="hljs-string">"style.css"</span>&gt;
&lt;/head&gt;

&lt;body&gt;
    &lt;div <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">container</span>"&gt;
        &lt;<span class="hljs-title">h2</span>&gt;<span class="hljs-title">User</span> <span class="hljs-title">Registration</span>&lt;/<span class="hljs-title">h2</span>&gt;
        &lt;<span class="hljs-title">form</span> <span class="hljs-title">action</span>="<span class="hljs-title">register</span>.<span class="hljs-title">php</span>" <span class="hljs-title">method</span>="<span class="hljs-title">post</span>"&gt;
            &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">form</span>-<span class="hljs-title">group</span>"&gt;
                &lt;<span class="hljs-title">label</span> <span class="hljs-title">for</span>="<span class="hljs-title">name</span>"&gt;<span class="hljs-title">Name</span>:&lt;/<span class="hljs-title">label</span>&gt;
                &lt;<span class="hljs-title">input</span> <span class="hljs-title">type</span>="<span class="hljs-title">text</span>" <span class="hljs-title">id</span>="<span class="hljs-title">name</span>" <span class="hljs-title">name</span>="<span class="hljs-title">name</span>" <span class="hljs-title">required</span>&gt;
            &lt;/<span class="hljs-title">div</span>&gt;
            &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">form</span>-<span class="hljs-title">group</span>"&gt;
                &lt;<span class="hljs-title">label</span> <span class="hljs-title">for</span>="<span class="hljs-title">username</span>"&gt;<span class="hljs-title">Username</span>:&lt;/<span class="hljs-title">label</span>&gt;
                &lt;<span class="hljs-title">input</span> <span class="hljs-title">type</span>="<span class="hljs-title">text</span>" <span class="hljs-title">id</span>="<span class="hljs-title">username</span>" <span class="hljs-title">name</span>="<span class="hljs-title">username</span>" <span class="hljs-title">required</span>&gt;
            &lt;/<span class="hljs-title">div</span>&gt;
            &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">form</span>-<span class="hljs-title">group</span>"&gt;
                &lt;<span class="hljs-title">label</span> <span class="hljs-title">for</span>="<span class="hljs-title">password</span>"&gt;<span class="hljs-title">Password</span>:&lt;/<span class="hljs-title">label</span>&gt;
                &lt;<span class="hljs-title">input</span> <span class="hljs-title">type</span>="<span class="hljs-title">password</span>" <span class="hljs-title">id</span>="<span class="hljs-title">password</span>" <span class="hljs-title">name</span>="<span class="hljs-title">password</span>" <span class="hljs-title">required</span>&gt;
            &lt;/<span class="hljs-title">div</span>&gt;
            &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">form</span>-<span class="hljs-title">group</span>"&gt;
                &lt;<span class="hljs-title">input</span> <span class="hljs-title">type</span>="<span class="hljs-title">submit</span>" <span class="hljs-title">value</span>="<span class="hljs-title">Register</span>"&gt;
            &lt;/<span class="hljs-title">div</span>&gt;
        &lt;/<span class="hljs-title">form</span>&gt;
    &lt;/<span class="hljs-title">div</span>&gt;
&lt;/<span class="hljs-title">body</span>&gt;

&lt;/<span class="hljs-title">html</span>&gt;</span>
</code></pre>
<p><strong>style.css</strong>:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span>,
<span class="hljs-selector-tag">html</span> {
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">font-family</span>: Arial, sans-serif;
}

<span class="hljs-selector-class">.container</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">8px</span>;
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">10px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.1</span>);
  <span class="hljs-attribute">width</span>: <span class="hljs-number">300px</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> auto;
}

<span class="hljs-selector-tag">h2</span> {
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-selector-class">.form-group</span> {
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-selector-tag">label</span> {
  <span class="hljs-attribute">font-weight</span>: bold;
}

<span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=<span class="hljs-string">"text"</span>]</span>,
<span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=<span class="hljs-string">"password"</span>]</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">8px</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#ccc</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">4px</span>;
  <span class="hljs-attribute">box-sizing</span>: border-box;
}

<span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=<span class="hljs-string">"submit"</span>]</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#007bff</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">4px</span>;
  <span class="hljs-attribute">cursor</span>: pointer;
}

<span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=<span class="hljs-string">"submit"</span>]</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#0056b3</span>;
}
</code></pre>
<p>Note: Ensure that these files are placed in the root directory of your project. The user interface will appear as follows:</p>
<p>Registration process:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/1_KOO1tlf51t0fBLoYvVm9-w.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>user registration form</em></p>
<p>Successful registration:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/1_elpUg7Wz7NIguur_xKYU6w.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>successful registration page</em></p>
<p>Our database structure is illustrated in the image below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/1_ZWe06DjCYU3iorRAGBGi8w.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>database structure on phpMyAdmin</em></p>
<p>Kudos! You deserve a big glass of juice for getting to this point, now let’s get to the next part, which is creating an JWT from scratch!</p>
<h3 id="heading-setting-up-the-jwt-class">Setting up the JWT Class</h3>
<p>In our project template, the <strong>Jwt.php</strong> file has already been created. Now, let’s proceed to create our <code>Jwt</code> class and implement the logic for encoding and generating a JWT token.</p>
<h3 id="heading-encoding-to-jwt">Encoding To JWT</h3>
<p>In order to create a JWT, we need to convert our header, payload, and signature to base64url encoding. However, PHP doesn’t support the Base64URL standard, Therefore, we will develop our custom Base64URL encoding method to perform the necessary encoding operation.</p>
<p>Please copy the following code snippet and paste it into the <code>Jwt</code> class located in the <strong>src</strong> folder.</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Jwt</span>
</span>{

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> <span class="hljs-keyword">string</span> $key</span>)
    </span>{

    }


    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">base64URLEncode</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $text</span>): <span class="hljs-title">string</span>
    </span>{

        <span class="hljs-keyword">return</span> str_replace([<span class="hljs-string">'+'</span>, <span class="hljs-string">'/'</span>, <span class="hljs-string">'='</span>], [<span class="hljs-string">'-'</span>, <span class="hljs-string">'_'</span>, <span class="hljs-string">''</span>], base64_encode($text));
    }


}
</code></pre>
<p>This class is responsible for encoding JWT tokens using the base64url encoding scheme. It includes a constructor that accepts a key parameter, which presumably represents the secret key used for encoding the tokens. Additionally, it contains a private method named <code>base64URLEncode</code>, which performs the base64URL encoding operation.</p>
<p><strong>The base64URLEncode Method:</strong> The base64urlEncode method is a private function within the <code>Jwt</code> class. It takes a string parameter, text, and returns the base64URL encoded version of the input string. The method first applies the standard base64 encoding to the input text using the base64_encode function.</p>
<p>Then, it replaces the characters ‘+’ (plus), ‘/’ (slash), and ‘=’ (equals sign) with ‘-’ (hyphen), ‘_’ (underscore), and an empty string, respectively. This substitution is necessary to ensure compatibility with the base64URL encoding scheme, which uses URL-safe characters. Finally, the method returns the base64URL encoded string.</p>
<p>Overall, the base64URLEncode method provides a crucial functionality for encoding data in JWT tokens using the base64URL encoding scheme, which is commonly used in JWT implementations.</p>
<h3 id="heading-the-encode-method">The encode Method</h3>
<p>Paste the following code snippet in your <code>Jwt</code> class:</p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">encode</span>(<span class="hljs-params"><span class="hljs-keyword">array</span> $payload</span>): <span class="hljs-title">string</span>
    </span>{

        $header = json_encode([
            <span class="hljs-string">"alg"</span> =&gt; <span class="hljs-string">"HS256"</span>,
            <span class="hljs-string">"typ"</span> =&gt; <span class="hljs-string">"JWT"</span>
        ]);

        $header = <span class="hljs-keyword">$this</span>-&gt;base64URLEncode($header);
        $payload = json_encode($payload);
        $payload = <span class="hljs-keyword">$this</span>-&gt;base64URLEncode($payload);

        $signature = hash_hmac(<span class="hljs-string">"sha256"</span>, $header . <span class="hljs-string">"."</span> . $payload, <span class="hljs-keyword">$this</span>-&gt;key, <span class="hljs-literal">true</span>);
        $signature = <span class="hljs-keyword">$this</span>-&gt;base64URLEncode($signature);
        <span class="hljs-keyword">return</span> $header . <span class="hljs-string">"."</span> . $payload . <span class="hljs-string">"."</span> . $signature;
    }
</code></pre>
<p>First, we have a class called <code>Jwt</code>. This class helps us create JWT tokens, In the constructor of the <code>Jwt</code> class, we specified a secret key. This secret key is important for creating and verifying the tokens on the signature component.</p>
<p>The <code>encode</code> method is where the magic happens. It takes some data (which we call the payload) and turns it into a JWT token. Here’s how it works:</p>
<ol>
<li>We create a header for the token. This header contains information about how the token is encrypted and what type of token it is. We then turn this header into a base64URL format.</li>
<li>Next, we take the payload data (the information we want to include in the token) and turn that into a base64URL format too.</li>
<li>After that, we combine the encoded header and payload with our secret key to create a signature. This signature helps ensure that the token hasn’t been tampered with.</li>
<li>Finally, we put everything together; the encoded header, payload, and signature to create the final JWT token. This token is what we can use in our applications to authenticate users and authorize access to certain resources.</li>
</ol>
<p>The base64URLEncode method ensures that data is encoded in a format suitable for URLs, making it safe for transmission over the web. Within our <code>Jwt</code> class, this method is employed internally by the encode function to encode both the header and payload sections of the token.</p>
<p>With that being said, let’s proceed to test and see our first JWT token, hurray!</p>
<h3 id="heading-the-login-endpoint">The Login Endpoint</h3>
<p>In our project, the <strong>api</strong> folder serves as the entry point for requests. Now that we’ve implemented the algorithm to encode and create a JWT token, let’s proceed to test it. To do this, we’ll create a <strong>login.php</strong> file within our <strong>api</strong> folder. In this file, we’ll send a request containing the username and password of the user profiled or created in our frontend <strong>register.php</strong> UI. We’ll pass the required user details in JSON format:</p>
<pre><code class="lang-php">{
    <span class="hljs-string">"username"</span>: <span class="hljs-string">"test"</span>,
    <span class="hljs-string">"password"</span>: <span class="hljs-string">"12345"</span>
}
</code></pre>
<p>Please integrate the following code snippet into the <strong>login.php</strong> file located within our <strong>api</strong> directory:</p>
<pre><code class="lang-php">
<span class="hljs-keyword">require</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">'/bootstrap.php'</span>;

<span class="hljs-keyword">if</span> ($_SERVER[<span class="hljs-string">'REQUEST_METHOD'</span>] !== <span class="hljs-string">'POST'</span>) {
    http_response_code(<span class="hljs-number">405</span>);
    header(<span class="hljs-string">'ALLOW: POST'</span>);
    <span class="hljs-keyword">exit</span>();
}

$contentType = <span class="hljs-keyword">isset</span>($_SERVER[<span class="hljs-string">"CONTENT_TYPE"</span>]) ? trim($_SERVER[<span class="hljs-string">"CONTENT_TYPE"</span>]) : <span class="hljs-string">''</span>;


<span class="hljs-keyword">if</span> ($contentType !== <span class="hljs-string">'application/json'</span>) {
    http_response_code(<span class="hljs-number">415</span>);
    <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"Only JSON content is supported"</span>]);
    <span class="hljs-keyword">exit</span>();
}

$data = json_decode(file_get_contents(<span class="hljs-string">'php://input'</span>), <span class="hljs-literal">true</span>);

<span class="hljs-keyword">if</span> ($data === <span class="hljs-literal">null</span>) {
    http_response_code(<span class="hljs-number">400</span>);
    <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"Invalid JSON data"</span>]);
    <span class="hljs-keyword">exit</span>();
}


<span class="hljs-keyword">if</span> (!array_key_exists(<span class="hljs-string">'username'</span>, $data) || !array_key_exists(<span class="hljs-string">'password'</span>, $data)) {
    http_response_code(<span class="hljs-number">400</span>);
    <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"Missing login credentials"</span>]);
    <span class="hljs-keyword">exit</span>();
}
</code></pre>
<p>This code snippet serves as the backend logic for handling user login requests. It begins by including the <strong>bootstrap.php</strong> file to initialize essential components. Then, it checks if the incoming request method is POST, returning a “Method Not Allowed” error if not. </p>
<p>Next, it verifies that the content type of the request is JSON, responding with an “Unsupported Media Type” error if not. The code proceeds to decode the JSON data from the request body and checks its validity. If the JSON data is invalid or lacks the “username” and “password” keys, it returns a “Bad Request” error.</p>
<p>Before proceeding with our login endpoint, we need to configure our <code>UserGateway</code> class, which is already available in our project template within the <strong>src</strong> folder. This class facilitates interaction with the user data in the database. The provided snippet initializes the class and defines a method <code>getByUsername()</code> to fetch user data based on the provided username.</p>
<pre><code class="lang-php">
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserGateway</span>
</span>{

    <span class="hljs-keyword">private</span> PDO $conn;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">Database $database</span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;conn = $database-&gt;getConnection();
    }


    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getByUsername</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $username</span>): <span class="hljs-title">array</span> | <span class="hljs-title">false</span>
    </span>{
        $sql = <span class="hljs-string">'SELECT * FROM user WHERE username = :username'</span>;
        $stmt = <span class="hljs-keyword">$this</span>-&gt;conn-&gt;prepare($sql);
        $stmt-&gt;bindValue(<span class="hljs-string">':username'</span>, $username, PDO::PARAM_STR);

        $stmt-&gt;execute();

        <span class="hljs-keyword">return</span> $stmt-&gt;fetch(PDO::FETCH_ASSOC);
    }
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/1_Tc_Mdl0618eD5ZPmfv-mEA.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>You will see the need for this as we go on.</p>
<p>Proceed to <strong>login.php</strong>.</p>
<p>Okay after that quick commercial break, we can create a class instance called <code>$user_gateway</code> and pass our <code>$database</code> connection to it. Next, we retrieve user data based on the provided username from the <code>$user_gateway</code> instance using the <code>getByUsername()</code> method. If no user is found (indicating invalid authentication), we return a 401 HTTP response status along with a corresponding error message in JSON format. </p>
<p>We validate the provided password against the hashed password stored in the user data. If the password verification fails, we return a similar 401 status and error message. If authentication is successful, we construct a payload containing the user's ID and name. Subsequently, we create a JWT token by encoding the payload using the <code>Jwt</code> class instantiated with the secret key from the environment variables. Finally, we respond with the generated token in JSON format, allowing access to protected resources, which will be implemented in a later section.</p>
<p>The code to implement this logic would be the following:</p>
<pre><code class="lang-php">$user_gateway = <span class="hljs-keyword">new</span> UserGateway($database);

$user = $user_gateway-&gt;getByUsername($data[<span class="hljs-string">'username'</span>]);

<span class="hljs-keyword">if</span> ($user === <span class="hljs-literal">false</span>) {
    http_response_code(<span class="hljs-number">401</span>);
    <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"invalid authentication"</span>]);
    <span class="hljs-keyword">exit</span>;
}

<span class="hljs-keyword">if</span> (!password_verify($data[<span class="hljs-string">'password'</span>], $user[<span class="hljs-string">'password_hash'</span>])) {
    http_response_code(<span class="hljs-number">401</span>);
    <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"invalid authentication"</span>]);
    <span class="hljs-keyword">exit</span>;
}


$payload = [
    <span class="hljs-string">"id"</span> =&gt; $user[<span class="hljs-string">'id'</span>],
    <span class="hljs-string">"name"</span> =&gt; $user[<span class="hljs-string">"name"</span>]
];


$JwtController = <span class="hljs-keyword">new</span> Jwt($_ENV[<span class="hljs-string">"SECRET_KEY"</span>]);

$token =$$JwtController-&gt;encode($payload);

<span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"token"</span> =&gt; $token]);
</code></pre>
<p>Full <strong>login.php</strong> code:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">require</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">'/bootstrap.php'</span>;

<span class="hljs-keyword">if</span> ($_SERVER[<span class="hljs-string">'REQUEST_METHOD'</span>] !== <span class="hljs-string">'POST'</span>) {
    http_response_code(<span class="hljs-number">405</span>);
    header(<span class="hljs-string">'ALLOW: POST'</span>);
    <span class="hljs-keyword">exit</span>();
}

$contentType = <span class="hljs-keyword">isset</span>($_SERVER[<span class="hljs-string">"CONTENT_TYPE"</span>]) ? trim($_SERVER[<span class="hljs-string">"CONTENT_TYPE"</span>]) : <span class="hljs-string">''</span>;


<span class="hljs-keyword">if</span> ($contentType !== <span class="hljs-string">'application/json'</span>) {
    http_response_code(<span class="hljs-number">415</span>);
    <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"Only JSON content is supported"</span>]);
    <span class="hljs-keyword">exit</span>();
}

$data = json_decode(file_get_contents(<span class="hljs-string">'php://input'</span>), <span class="hljs-literal">true</span>);

<span class="hljs-keyword">if</span> ($data === <span class="hljs-literal">null</span>) {
    http_response_code(<span class="hljs-number">400</span>);
    <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"Invalid JSON data"</span>]);
    <span class="hljs-keyword">exit</span>();
}


<span class="hljs-keyword">if</span> (!array_key_exists(<span class="hljs-string">'username'</span>, $data) || !array_key_exists(<span class="hljs-string">'password'</span>, $data)) {
    http_response_code(<span class="hljs-number">400</span>);
    <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"Missing login credentials"</span>]);
    <span class="hljs-keyword">exit</span>();
}

$user_gateway = <span class="hljs-keyword">new</span> UserGateway($database);

$user = $user_gateway-&gt;getByUsername($data[<span class="hljs-string">'username'</span>]);

<span class="hljs-keyword">if</span> ($user === <span class="hljs-literal">false</span>) {
    http_response_code(<span class="hljs-number">401</span>);
    <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"invalid authentication"</span>]);
    <span class="hljs-keyword">exit</span>;
}

<span class="hljs-keyword">if</span> (!password_verify($data[<span class="hljs-string">'password'</span>], $user[<span class="hljs-string">'password_hash'</span>])) {
    http_response_code(<span class="hljs-number">401</span>);
    <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"invalid authentication"</span>]);
    <span class="hljs-keyword">exit</span>;
}


<span class="hljs-keyword">require</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">"/tokens.php"</span>;

$refresh_token_gateway = <span class="hljs-keyword">new</span> RefreshTokenGateway($database, $_ENV[<span class="hljs-string">"SECRET_KEY"</span>]);

$refresh_token_gateway-&gt;create($refresh_token, $refresh_token_expiry);
</code></pre>
<p>Now that we have set up our login endpoint, established database connections, and implemented the JWT encoding algorithm, nothing stands in our way of obtaining our first JWT token. Let us proceed to test our application with the following steps:</p>
<ol>
<li>Please navigate to our user interface for registering users. The URL should be <a target="_blank" href="http://localhost/php_auth_jwt_tut/register.php">http://localhost/php_auth_jwt_tut/register.php</a> if you followed the project structure.</li>
<li>Send the username and password of the created user to the login endpoint (<a target="_blank" href="http://localhost/php_auth_jwt_tut/register.php">http://localhost/php_auth_jwt_tut/api/login.php</a>) in JSON format, like this, and fire the request:</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/1_Yrpa_En9sjEKsK9ruO_jhg.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>endpoint testing</em></p>
<p>Voila! Just like that, we obtain our JWT token!</p>
<h2 id="heading-protected-resources-and-decoding-json-web-tokens">Protected Resources And Decoding JSON Web Tokens</h2>
<p>Having successfully generated a JWT token, let us now explore how we can safeguard our resources and verify the token’s contents by decoding it.</p>
<p>You’ll find that our controller classes, <code>StudentController.php</code>, and the gateway class <code>StudentGateway.php</code>, situated in the <strong>src</strong> folder, has already been configured with essential methods. Now, all that's left is to instantiate these classes in our <strong>index.php</strong>, serving as the entry point for our requests in the <strong>api</strong> folder.</p>
<p>To do this add the following code snippet in the <strong>index.php</strong> file located at the <strong>api</strong> folder of our project:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">require</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">'/bootstrap.php'</span>;

<span class="hljs-keyword">if</span> ($_SERVER[<span class="hljs-string">'REQUEST_METHOD'</span>] !== <span class="hljs-string">'POST'</span>) {
    http_response_code(<span class="hljs-number">405</span>);
    header(<span class="hljs-string">'ALLOW: POST'</span>);
    <span class="hljs-keyword">exit</span>();
}

$contentType = <span class="hljs-keyword">isset</span>($_SERVER[<span class="hljs-string">"CONTENT_TYPE"</span>]) ? trim($_SERVER[<span class="hljs-string">"CONTENT_TYPE"</span>]) : <span class="hljs-string">''</span>;


<span class="hljs-keyword">if</span> ($contentType !== <span class="hljs-string">'application/json'</span>) {
    http_response_code(<span class="hljs-number">415</span>);
    <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"Only JSON content is supported"</span>]);
    <span class="hljs-keyword">exit</span>();
}

$data = json_decode(file_get_contents(<span class="hljs-string">'php://input'</span>), <span class="hljs-literal">true</span>);

<span class="hljs-keyword">if</span> ($data === <span class="hljs-literal">null</span>) {
    http_response_code(<span class="hljs-number">400</span>);
    <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"Invalid JSON data"</span>]);
    <span class="hljs-keyword">exit</span>();
}


<span class="hljs-keyword">if</span> (!array_key_exists(<span class="hljs-string">'username'</span>, $data) || !array_key_exists(<span class="hljs-string">'password'</span>, $data)) {
    http_response_code(<span class="hljs-number">400</span>);
    <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"Missing login credentials"</span>]);
    <span class="hljs-keyword">exit</span>();
}

$user_gateway = <span class="hljs-keyword">new</span> UserGateway($database);

$user = $user_gateway-&gt;getByUsername($data[<span class="hljs-string">'username'</span>]);

<span class="hljs-keyword">if</span> ($user === <span class="hljs-literal">false</span>) {
    http_response_code(<span class="hljs-number">401</span>);
    <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"invalid authentication"</span>]);
    <span class="hljs-keyword">exit</span>;
}

<span class="hljs-keyword">if</span> (!password_verify($data[<span class="hljs-string">'password'</span>], $user[<span class="hljs-string">'password_hash'</span>])) {
    http_response_code(<span class="hljs-number">401</span>);
    <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"invalid authentication"</span>]);
    <span class="hljs-keyword">exit</span>;
}


$payload = [
    <span class="hljs-string">"id"</span> =&gt; $user[<span class="hljs-string">'id'</span>],
    <span class="hljs-string">"name"</span> =&gt; $user[<span class="hljs-string">"name"</span>]
];


$JwtController = <span class="hljs-keyword">new</span> Jwt($_ENV[<span class="hljs-string">"SECRET_KEY"</span>]);

$token =$JwtController-&gt;encode($payload);

<span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"token"</span> =&gt; $token]);

$user = <span class="hljs-keyword">new</span> UserGateway($database);


$gateway = <span class="hljs-keyword">new</span> StudentGateway($database);

$controller = <span class="hljs-keyword">new</span> StudentController($gateway);


$controller-&gt;processRequest($_SERVER[<span class="hljs-string">'REQUEST_METHOD'</span>]);
</code></pre>
<p>How the files are structured at this current stage:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/1_MAuYnkgxspnOmgDINUvkSQ.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>file structure on VS Code</em></p>
<p>Please note that upon testing the endpoint (<a target="_blank" href="http://localhost/phpAuthJWT/api">http://localhost/phpAuthJWT/api</a>) at this point, you’ll receive the following result, without any restrictions applied:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/1__c8i8N9Vm4MGaZK4alfnQA.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>endpoint testing</em></p>
<p>Note: After setting up the database connection and importing the provided file, <strong>college.sql</strong>, as instructed, the tables, including the “students” table, are populated with pre-added data. This enables us to view the student details that are currently visible.</p>
<h3 id="heading-what-happens-now">What Happens Now?</h3>
<p>We establish a custom URL endpoint to retrieve data via the GET HTTP method. The URL, <code>[http://localhost/phpAuthJWT/api/](http://localhost/phpAuthJWT/api/getALLStudents)getAllStudents</code>, will remain functional due to the server configuration specified in our <strong>.htaccess</strong> file located within the <strong>api</strong> folder. When making requests to this URL, we’ll include our token in the header using the standard HTTP Authorization request header, adhering to the bearer token format:</p>
<p>Authorization: Bearer </p>
<p>In our <strong>src</strong> folder, we have set up an Auth class where we will create a method to validate the JWT token. This method verifies if the token is provided in the HTTP header and decodes it.</p>
<h2 id="heading-how-to-set-up-the-decode-method-in-our-jwt-class">How to Set Up The Decode Method In Our JWT Class</h2>
<p>When setting up the decoding functionality in the <code>Jwt</code> class, as we did with the encoding method, we will ensure that our <code>Jwt</code> class, located in the <strong>src</strong> folder of our project within the <strong>jwt.php</strong> file handles this task. To achieve this, we will incorporate the following code snippets into our <code>Jwt</code> class – the new methods are the <code>decode</code> and <code>base64UrlDecode</code> methods, thus completing its structure. The final code will resemble the following:</p>
<pre><code class="lang-php">
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Jwt</span>
</span>{

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> <span class="hljs-keyword">string</span> $key</span>)
    </span>{

    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">encode</span>(<span class="hljs-params"><span class="hljs-keyword">array</span> $payload</span>): <span class="hljs-title">string</span>
    </span>{

        $header = json_encode([
            <span class="hljs-string">"alg"</span> =&gt; <span class="hljs-string">"HS256"</span>,
            <span class="hljs-string">"typ"</span> =&gt; <span class="hljs-string">"JWT"</span>
        ]);

        $header = <span class="hljs-keyword">$this</span>-&gt;base64URLEncode($header);
        $payload = json_encode($payload);
        $payload = <span class="hljs-keyword">$this</span>-&gt;base64URLEncode($payload);

        $signature = hash_hmac(<span class="hljs-string">"sha256"</span>, $header . <span class="hljs-string">"."</span> . $payload, <span class="hljs-keyword">$this</span>-&gt;key, <span class="hljs-literal">true</span>);
        $signature = <span class="hljs-keyword">$this</span>-&gt;base64URLEncode($signature);
        <span class="hljs-keyword">return</span> $header . <span class="hljs-string">"."</span> . $payload . <span class="hljs-string">"."</span> . $signature;
    }



    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">decode</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $token</span>): <span class="hljs-title">array</span>
    </span>{
        <span class="hljs-keyword">if</span> (
            preg_match(
                <span class="hljs-string">"/^(?&lt;header&gt;.+)\.(?&lt;payload&gt;.+)\.(?&lt;signature&gt;.+)$/"</span>,
                $token,
                $matches
            ) !== <span class="hljs-number">1</span>
        ) {

            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">InvalidArgumentException</span>(<span class="hljs-string">"invalid token format"</span>);
        }

        $signature = hash_hmac(
            <span class="hljs-string">"sha256"</span>,
            $matches[<span class="hljs-string">"header"</span>] . <span class="hljs-string">"."</span> . $matches[<span class="hljs-string">"payload"</span>],
            <span class="hljs-keyword">$this</span>-&gt;key,
            <span class="hljs-literal">true</span>
        );

        $signature_from_token = <span class="hljs-keyword">$this</span>-&gt;base64URLDecode($matches[<span class="hljs-string">"signature"</span>]);

        <span class="hljs-keyword">if</span> (!hash_equals($signature, $signature_from_token)) {

            <span class="hljs-comment">// throw new Exception("signature doesn't match");</span>
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> InvalidSignatureException;
        }

        $payload = json_decode(<span class="hljs-keyword">$this</span>-&gt;base64URLDecode($matches[<span class="hljs-string">"payload"</span>]), <span class="hljs-literal">true</span>);

        <span class="hljs-keyword">return</span> $payload;
    }


    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">base64URLEncode</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $text</span>): <span class="hljs-title">string</span>
    </span>{

        <span class="hljs-keyword">return</span> str_replace([<span class="hljs-string">'+'</span>, <span class="hljs-string">'/'</span>, <span class="hljs-string">'='</span>], [<span class="hljs-string">'-'</span>, <span class="hljs-string">'_'</span>, <span class="hljs-string">''</span>], base64_encode($text));
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">base64URLDecode</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $text</span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> base64_decode(
            str_replace(
                [<span class="hljs-string">"-"</span>, <span class="hljs-string">"_"</span>],
                [<span class="hljs-string">"+"</span>, <span class="hljs-string">"/"</span>],
                $text
            )
        );
    }


}
</code></pre>
<h3 id="heading-decode-method">Decode Method:</h3>
<p>The <code>decode</code> method is responsible for decoding a JWT token into its respective header and payload components. Here's a brief overview of what it does:</p>
<ol>
<li><strong>Token Validation</strong>: First, it verifies if the provided token follows the expected format of three sections separated by periods.</li>
<li><strong>Signature Verification</strong>: It recalculates the signature based on the header and payload from the token and compares it with the signature provided in the token. This step ensures the integrity of the token.</li>
<li><strong>Payload Extraction</strong>: If the signature verification passes, it decodes the payload component of the token from base64 URL encoding into a JSON format. This decoded payload contains information about the user associated with the token.</li>
<li>Finally, it returns the decoded payload as an associative array.</li>
</ol>
<h3 id="heading-base64urldecode-method">base64URLDecode Method:</h3>
<p>The <code>base64URLDecode</code> method is a helper function used specifically for decoding strings that have been encoded using base64 URL encoding. Here's a breakdown of its functionality:</p>
<ol>
<li><strong>Replace Characters</strong>: It first replaces the characters <code>-</code> and <code>_</code> in the encoded string with <code>+</code> and <code>/</code> respectively. This step is necessary because URL encoding replaces certain characters for safe transmission over the web.</li>
<li><strong>Base64 Decoding</strong>: After character replacement, it performs the standard base64 decoding operation on the modified string.</li>
<li>Finally, it returns the decoded string.</li>
</ol>
<p>In summary, the <code>decode</code> method validates and extracts the payload from a JWT token, while the <code>base64URLDecode</code> method assists in decoding strings encoded using base64 URL encoding, ensuring the integrity and accuracy of the decoded data.</p>
<h3 id="heading-protected-resources">Protected Resources</h3>
<p>Now that we have completed the setup, let’s finalize our <code>Jwt</code> class. It’s essential to restrict access to our endpoints without the required authorization header. For instance, accessing the URL <code>[http://localhost/phpAuthJWT/api/](http://localhost/phpAuthJWT/api/getALLStudents)getAllStudents</code> should be restricted if the necessary authorization header is absent, and access to resources should be denied if the URL is incorrect.</p>
<p>To achieve this, add the following code snippet to the top of your <strong>index.php</strong> file, which serves as the entry point for accessing our student data. Paste this code after importing the <strong>bootstrap.php</strong> configuration file.</p>
<pre><code class="lang-php"><span class="hljs-keyword">require</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">'/bootstrap.php'</span>;

$path = parse_url($_SERVER[<span class="hljs-string">"REQUEST_URI"</span>], PHP_URL_PATH);

$parts = explode(<span class="hljs-string">"/"</span>, $path);


$resource = $parts[<span class="hljs-number">3</span>];

$id = $parts[<span class="hljs-number">4</span>] ?? <span class="hljs-literal">null</span>;

<span class="hljs-keyword">if</span> ($resource != <span class="hljs-string">"getAllStudents"</span>) {

    http_response_code(<span class="hljs-number">404</span>);
    <span class="hljs-keyword">exit</span>;
}
</code></pre>
<p>This snippet shows how we extracted the path from the requested URI using the <code>parse_url()</code> function, isolating the endpoint accessed by the user. Then splitting the path into segments using the <code>explode()</code> function, allowing us to identify the requested resource. If the requested resource is not “getAllStudents”, indicating an invalid endpoint, the code responds with a 404 Not Found status code, signaling that the requested resource does not exist. This ensures that only valid endpoints can be accessed, preventing unauthorized access to our API’s resources.</p>
<p>Note: To verify that our project is functioning as intended, send a request to the “getAllStudents” endpoint at http://localhost/phpAuthJWT/api/getAllStudents</p>
<p>This request will help us ensure that our API is correctly configured and capable of retrieving all student data.</p>
<h3 id="heading-checking-the-headers-for-the-correct-authorization-scheme">Checking The Headers For The Correct Authorization Scheme</h3>
<p>We have established a custom URL, but it is crucial to verify that the JWT token provided in the header is valid. To accomplish this, we will utilize the Auth class, which is already available in our project’s <strong>src</strong> folder. This class, which was provided with our project template, will assist in ensuring the integrity of the JWT token.</p>
<p><strong>Auth.php</strong>:</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Auth</span>
</span>{



    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> UserGateway $user_gateway, <span class="hljs-keyword">private</span> Jwt $JwtCtrl</span>)
    </span>{
    }



    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">authenticateJWTToken</span>(<span class="hljs-params"></span>): <span class="hljs-title">bool</span>
    </span>{

        <span class="hljs-keyword">if</span> (!preg_match(<span class="hljs-string">"/^Bearer\s+(.*)$/"</span>, $_SERVER[<span class="hljs-string">"HTTP_AUTHORIZATION"</span>], $matches)) {
            http_response_code(<span class="hljs-number">400</span>);
            <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"incomplete authorization header"</span>]);
            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
        }

        <span class="hljs-keyword">try</span> {
            $data = <span class="hljs-keyword">$this</span>-&gt;JwtCtrl-&gt;decode($matches[<span class="hljs-number">1</span>]);
        } <span class="hljs-keyword">catch</span> (InvalidSignatureException) {

            http_response_code(<span class="hljs-number">401</span>);
            <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"invalid signature"</span>]);
            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
        } <span class="hljs-keyword">catch</span> (<span class="hljs-built_in">Exception</span> $e) {

            http_response_code(<span class="hljs-number">400</span>);
            <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; $e-&gt;getMessage()]);
            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
        }



        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }
}
</code></pre>
<p>This class is responsible for handling the authentication of JWT tokens. Within the class, we have a constructor method that initializes the <code>Auth</code> object with instances of two other classes: <code>UserGateway</code> and <code>Jwt</code>.</p>
<p>Absolutely! Let’s break down the code snippet in a more detailed and narrative manner:</p>
<p>In the provided PHP code snippet, we defined a class named <code>Auth</code>. This class is responsible for handling the authentication of JWT tokens. Within the class, we have a constructor method that initializes the <code>Auth</code> object with instances of two other classes: <code>UserGateway</code> and <code>Jwt</code>.</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Auth</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> UserGateway $user_gateway, <span class="hljs-keyword">private</span> Jwt $JwtCtrl</span>)
    </span>{
    }
    <span class="hljs-comment">// Other methods will go here...</span>
}
</code></pre>
<p>The constructor method allows the <code>Auth</code> class to interact with user data through the <code>UserGateway</code> class and handle JWT tokens using the <code>Jwt</code> class.</p>
<p>Next, we have a method called <code>authenticateJWTToken()</code>, which is tasked with verifying the validity of a JWT token present in the HTTP authorization header of incoming requests.</p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">authenticateJWTToken</span>(<span class="hljs-params"></span>): <span class="hljs-title">bool</span>
</span>{

}
</code></pre>
<p>Within the <code>authenticateJWTToken()</code> method, the code first checks if the authorization header is properly formatted and contains a valid JWT token.</p>
<pre><code class="lang-php"><span class="hljs-keyword">if</span> (!preg_match(<span class="hljs-string">"/^Bearer\s+(.*)$/"</span>, $_SERVER[<span class="hljs-string">"HTTP_AUTHORIZATION"</span>], $matches)) {
    http_response_code(<span class="hljs-number">400</span>);
    <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"incomplete authorization header"</span>]);
    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
}
</code></pre>
<p>If the authorization header is incomplete or improperly formatted, the method returns a 400 Bad Request response along with a message indicating the issue.</p>
<p>Next, the code attempts to decode the JWT token using the <code>decode()</code> method of the <code>Jwt</code> class. If the decoding process fails due to an invalid signature or any other exception, appropriate HTTP response codes and error messages are returned.</p>
<pre><code class="lang-php"><span class="hljs-keyword">try</span> {
    $data = <span class="hljs-keyword">$this</span>-&gt;JwtCtrl-&gt;decode($matches[<span class="hljs-number">1</span>]);
} <span class="hljs-keyword">catch</span> (InvalidSignatureException) {
    http_response_code(<span class="hljs-number">401</span>);
    <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"invalid signature"</span>]);
    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
} <span class="hljs-keyword">catch</span> (<span class="hljs-built_in">Exception</span> $e) {
    http_response_code(<span class="hljs-number">400</span>);
    <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; $e-&gt;getMessage()]);
    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
}
</code></pre>
<p>If the JWT token is successfully decoded without any exceptions, the method returns <code>true</code>, indicating that the authentication process was successful.</p>
<p>The <code>authenticateJWTToken()</code> method ensures that incoming requests contain a valid JWT token in the Authorization header and handles various error scenarios gracefully to provide appropriate feedback to clients interacting with the API.</p>
<h2 id="heading-creating-instances-in-the-api-entry-point">Creating Instances In The API Entry Point</h2>
<p>Now that we have finished setting up our methods let us add our class instances to enable the protection of our resources from unauthorized users.</p>
<p><strong>index.php</strong>:</p>
<pre><code class="lang-php">
<span class="hljs-keyword">declare</span>(strict_types=<span class="hljs-number">1</span>);

<span class="hljs-keyword">require</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">'/bootstrap.php'</span>;

$path = parse_url($_SERVER[<span class="hljs-string">"REQUEST_URI"</span>], PHP_URL_PATH);

$parts = explode(<span class="hljs-string">"/"</span>, $path);


$resource = $parts[<span class="hljs-number">3</span>];

<span class="hljs-keyword">if</span> ($resource != <span class="hljs-string">"getAllStudents"</span>) {

    http_response_code(<span class="hljs-number">404</span>);
    <span class="hljs-keyword">exit</span>;
}


$user = <span class="hljs-keyword">new</span> UserGateway($database);


$JwtCtrl = <span class="hljs-keyword">new</span> Jwt($_ENV[<span class="hljs-string">"SECRET_KEY"</span>]);

$auth = <span class="hljs-keyword">new</span> Auth($user, $JwtCtrl);

<span class="hljs-keyword">if</span> (!$auth-&gt;authenticateJWTToken()) {
    <span class="hljs-keyword">exit</span>;
}



$gateway = <span class="hljs-keyword">new</span> StudentGateway($database);

$controller = <span class="hljs-keyword">new</span> StudentController($gateway);



$controller-&gt;processRequest($_SERVER[<span class="hljs-string">'REQUEST_METHOD'</span>]);
</code></pre>
<p>Once we’ve incorporated the provided snippet into our <strong>index.php</strong>, it's crucial to observe the different scenarios that occur when we access our API endpoint at <code>http://localhost/phpAuthJWT/api/getAllStudents</code>.</p>
<p>By accessing this URL, we can witness several possible outcomes, each indicative of a different state or functionality within our application. These outcomes may include:</p>
<ol>
<li><strong>Successful Response</strong>: If the authentication process is successful and the JWT token is valid, the API should return a response containing the desired data, such as a list of all students.</li>
<li><strong>Invalid Token</strong>: In case the JWT token provided in the request’s Authorization header is invalid, expired, or improperly formatted, the API should respond with an error message indicating the issue. This ensures that only authorized users can access the protected resources.</li>
<li><strong>Unauthorized Access</strong>: If the request does not include a JWT token or lacks proper authorization, the API should respond with a 401 Unauthorized status code, indicating that access to the requested resource is restricted.</li>
<li><strong>Invalid Endpoint</strong>: If the URL provided does not match any of the defined endpoints or routes within our application, the API should respond with a 404 Not Found status code, signaling that the requested resource does not exist.</li>
</ol>
<p>By examining these outcomes, we can gain insights into the functionality and reliability of our API, ensuring that it behaves as intended and provides appropriate responses to different types of requests and scenarios.</p>
<p>Working properly with Authorization Header: <code>http://localhost/phpAuthJWT/api/getAllStudents</code></p>
<p><img src="https://miro.medium.com/v2/resize:fit:700/1*KpQHCYFFD7qN7j2gjTvaBg.png" alt="Image" width="700" height="331" loading="lazy">
<em>endpoint testing</em></p>
<p>Not working properly without Authorization Header: <code>http://localhost/phpAuthJWT/api/getAllStudents</code></p>
<p><img src="https://miro.medium.com/v2/resize:fit:700/1*BCtXpT7RiFoMq2IshlTl3Q.png" alt="Image" width="700" height="305" loading="lazy">
<em>endpoint testing</em></p>
<h2 id="heading-suggestions">Suggestions</h2>
<p>After setting up our JWT, there’s a whole new world to explore. You can experiment with our API by creating custom URLs for specific tasks, such as finding students by name or letting users create and update their own student profiles by tracking the <code>user_id</code> of the user. You can use various HTTP methods like GET, POST, PATCH, and DELETE to manage data effectively. While this article covers the basics, there’s an abundance of possibilities waiting to be explored when comes to creating a robust API.</p>
<p>JWT tokens provide a convenient and efficient way to handle authentication and authorization in web applications. However, it’s crucial to recognize that they are not absolutely foolproof. It’s essential to avoid putting sensitive information in the payload component of the token, as the payload is typically base64URLEncoded and can be easily decoded. Additionally, the secret key used to sign the token should be kept hidden and never exposed to public information, as it can compromise the security of the system.</p>
<p>In JWT tokens, the header, payload, and signature are all base64URLEncoded, ensuring compatibility with URLs and safe transmission over the web. However, it’s important to note that JWT tokens should have an expiration time to mitigate the risk of token misuse. In the next part, we will explore how to implement token expiration and introduce refresh tokens to enhance the security of our authentication system. </p>
<p>We have explored the implementation of JSON Web Tokens (JWTs) and learned how to utilize them. However, a significant security concern persists: our tokens, specifically referred to as access tokens in this context, can currently access our resources indefinitely. This practice does not align with industry standards. To enhance security, we should implement token expiration for our JWTs. Additionally, adopting a two-token system comprising a refresh token alongside our access token is recommended.</p>
<h2 id="heading-how-to-implement-token-expiration">How to Implement Token Expiration</h2>
<p><img src="https://miro.medium.com/v2/resize:fit:630/1*iexXyX3pAwzlv3M-YPQJsg.jpeg" alt="Image" width="630" height="630" loading="lazy"></p>
<p>We'll focus on implementing access tokens and refresh tokens. Any necessary additions to our project or database structure will be introduced as we progress through the implementation.</p>
<p>Let's get right into it!</p>
<p>Access tokens must have an expiration mechanism. We need our JWT tokens to automatically expire after a short period, requiring users to request a new token once it expires. </p>
<p>Prompting users to log in every minute when the token expires is not user-friendly. Instead, we can issue a refresh token. The refresh token typically has a longer lifespan than the access token. When the access token expires, the client can leverage the refresh token to obtain a new access token. We will incorporate an endpoint for the client to refresh the access token seamlessly.</p>
<p>Continuing from where we left off, we will now create a refresh endpoint in our <strong>api</strong> folder. As we know this endpoint serves as our entry point for handling requests related to token refreshing and will be named <strong>refresh.php</strong>.</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-keyword">declare</span>(strict_types=<span class="hljs-number">1</span>);

<span class="hljs-keyword">require</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">"/bootstrap.php"</span>;

<span class="hljs-keyword">if</span> ($_SERVER[<span class="hljs-string">"REQUEST_METHOD"</span>] !== <span class="hljs-string">"POST"</span>) {

    http_response_code(<span class="hljs-number">405</span>);
    header(<span class="hljs-string">"Allow: POST"</span>);
    <span class="hljs-keyword">exit</span>;
}

$data = (<span class="hljs-keyword">array</span>) json_decode(file_get_contents(<span class="hljs-string">"php://input"</span>), <span class="hljs-literal">true</span>);

<span class="hljs-keyword">if</span> ( ! array_key_exists(<span class="hljs-string">"token"</span>, $data)) {

    http_response_code(<span class="hljs-number">400</span>);
    <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"missing token"</span>]);
    <span class="hljs-keyword">exit</span>;
}

$JwtController = <span class="hljs-keyword">new</span> Jwt($_ENV[<span class="hljs-string">"SECRET_KEY"</span>]);
</code></pre>
<p>It checks if the incoming request method is POST; otherwise, it responds with a 405 HTTP status code and allows only POST requests. The script then parses JSON data from the request body, ensuring it contains a “token” key. If the token is missing, it responds with a 400 status code and a JSON message indicating the absence of the token. Finally, the script initializes a <code>Jwt</code> object with a secret key from the environment variables for further token processing.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:630/1*qPsrno17jnQB-TiKQztLVQ.png" alt="Image" width="630" height="230" loading="lazy">
<em>refresh.php file</em></p>
<p>Before proceeding with the setup of our refresh endpoint, we will create a class called <code>RefreshTokenGateway.php</code> to handle operations related to refreshing tokens. The <code>RefreshTokenGateway</code> class includes methods for creating, deleting, fetching, and managing expired refresh tokens within our database.</p>
<p>The <code>RefreshTokenGateway</code> class utilizes a PDO connection and a secret key for hashing tokens. Its constructor initializes the database connection and secret key variables. The <code>create</code> method generates a hash for the token and inserts it into the <code>refresh_token</code> table along with its expiration time. The <code>delete</code> method removes a token from the database based on its hash value. The <code>getByToken</code> method retrieves token details based on its hash. Lastly, the <code>deleteExpired</code> method deletes expired tokens from the database, ensuring efficient token management.</p>
<p>Overall, the <code>RefreshTokenGateway</code> class provides essential functionality for maintaining and handling refresh tokens securely within our web application.</p>
<p><strong>RefreshTokenGateway.php</strong>:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RefreshTokenGateway</span>
</span>{
    <span class="hljs-keyword">private</span> PDO $conn;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">string</span> $key;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">Database $database, <span class="hljs-keyword">string</span> $key</span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;conn = $database-&gt;getConnection();
        <span class="hljs-keyword">$this</span>-&gt;key = $key;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">create</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $token, <span class="hljs-keyword">int</span> $expiry</span>): <span class="hljs-title">bool</span>
    </span>{
        $hash = hash_hmac(<span class="hljs-string">"sha256"</span>, $token, <span class="hljs-keyword">$this</span>-&gt;key);

        $sql = <span class="hljs-string">"INSERT INTO refresh_token (token_hash, expires_at)
                VALUES (:token_hash, :expires_at)"</span>;

        $stmt = <span class="hljs-keyword">$this</span>-&gt;conn-&gt;prepare($sql);

        $stmt-&gt;bindValue(<span class="hljs-string">":token_hash"</span>, $hash, PDO::PARAM_STR);
        $stmt-&gt;bindValue(<span class="hljs-string">":expires_at"</span>, $expiry, PDO::PARAM_INT);

        <span class="hljs-keyword">return</span> $stmt-&gt;execute();
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">delete</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $token</span>): <span class="hljs-title">int</span>
    </span>{
        $hash = hash_hmac(<span class="hljs-string">"sha256"</span>, $token, <span class="hljs-keyword">$this</span>-&gt;key);

        $sql = <span class="hljs-string">"DELETE FROM refresh_token
                WHERE token_hash = :token_hash"</span>;

        $stmt = <span class="hljs-keyword">$this</span>-&gt;conn-&gt;prepare($sql);

        $stmt-&gt;bindValue(<span class="hljs-string">":token_hash"</span>, $hash, PDO::PARAM_STR);

        $stmt-&gt;execute();

        <span class="hljs-keyword">return</span> $stmt-&gt;rowCount();
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getByToken</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $token</span>): <span class="hljs-title">array</span> | <span class="hljs-title">false</span>
    </span>{
        $hash = hash_hmac(<span class="hljs-string">"sha256"</span>, $token, <span class="hljs-keyword">$this</span>-&gt;key);

        $sql = <span class="hljs-string">"SELECT *
                FROM refresh_token
                WHERE token_hash = :token_hash"</span>;

        $stmt = <span class="hljs-keyword">$this</span>-&gt;conn-&gt;prepare($sql);

        $stmt-&gt;bindValue(<span class="hljs-string">":token_hash"</span>, $hash, PDO::PARAM_STR);

        $stmt-&gt;execute();

        <span class="hljs-keyword">return</span> $stmt-&gt;fetch(PDO::FETCH_ASSOC);
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">deleteExpired</span>(<span class="hljs-params"></span>): <span class="hljs-title">int</span>
    </span>{
        $sql = <span class="hljs-string">"DELETE FROM refresh_token
                WHERE expires_at &lt; UNIX_TIMESTAMP()"</span>;

        $stmt = <span class="hljs-keyword">$this</span>-&gt;conn-&gt;query($sql);

        <span class="hljs-keyword">return</span> $stmt-&gt;rowCount();
    }
}
</code></pre>
<h3 id="heading-updated-folder-structure">Updated Folder Structure</h3>
<p>From the code snippet provided for our <code>[RefreshTokenGateway](https://github.com/Oghenekparobo/php_auth_jwt_tut/blob/refresh-token/src/RefreshTokenGateway.php)</code> class, it's evident that a new table has been incorporated into our database. We have updated our <strong>college.sql</strong> file to accommodate this change. Kindly import the updated SQL file into your database, following the process outlined in the first part of this article.</p>
<p>Additionally, a new exception class named <code>TokenExpiredException</code> has been introduced. Ensure to update your project structure or files accordingly to include this new exception handling. This ensures that your project remains up-to-date and aligned with the latest changes in token management.</p>
<p>Before we finish setting up our refresh endpoint for obtaining a new access token after expiration, let’s integrate the retrieval of our refresh token and access token into our login endpoint. We have the <code>RefreshTokenGateway</code> class to manage refresh tokens, and we'll create the <strong>tokens.php</strong> file in our <strong>api</strong> folder for token creation, which will be used in both the refresh and login endpoints. This approach ensures a straightforward and unified token management process across our application.</p>
<p><strong>tokens.php</strong>:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

$payload = [
    <span class="hljs-string">"sub"</span> =&gt; $user[<span class="hljs-string">"id"</span>],
    <span class="hljs-string">"name"</span> =&gt; $user[<span class="hljs-string">"name"</span>],
    <span class="hljs-string">"exp"</span> =&gt; time() + <span class="hljs-number">20</span>
];

$JwtController = <span class="hljs-keyword">new</span> Jwt($_ENV[<span class="hljs-string">"SECRET_KEY"</span>]);

$access_token = $JwtController-&gt;encode($payload);

$refresh_token_expiry = time() + <span class="hljs-number">432000</span>;

$refresh_token = $JwtController-&gt;encode([
    <span class="hljs-string">"sub"</span> =&gt; $user[<span class="hljs-string">"id"</span>],
    <span class="hljs-string">"exp"</span> =&gt; $refresh_token_expiry
]);

<span class="hljs-keyword">echo</span> json_encode([
    <span class="hljs-string">"access_token"</span> =&gt; $access_token,
    <span class="hljs-string">"refresh_token"</span> =&gt; $refresh_token
]);
</code></pre>
<p>The main difference between the refresh token and the payload (access token claims) is that the payload contains detailed user information like ID and name, and its expiration is shorter (20 seconds) for security reasons. On the other hand, the refresh token only contains the user ID and has a longer expiration (5 days) to allow for longer-lasting authentication without needing frequent logins. This separation of tokens and their respective lifespans enhances security and user convenience in token-based authentication systems.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:630/1*0CqrZ5zsgvCHDyhiKRU53g.png" alt="Image" width="630" height="223" loading="lazy"></p>
<p><strong>login.php</strong>:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">require</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">'/bootstrap.php'</span>;

<span class="hljs-keyword">if</span> ($_SERVER[<span class="hljs-string">'REQUEST_METHOD'</span>] !== <span class="hljs-string">'POST'</span>) {
    http_response_code(<span class="hljs-number">405</span>);
    header(<span class="hljs-string">'ALLOW: POST'</span>);
    <span class="hljs-keyword">exit</span>();
}

$contentType = <span class="hljs-keyword">isset</span>($_SERVER[<span class="hljs-string">"CONTENT_TYPE"</span>]) ? trim($_SERVER[<span class="hljs-string">"CONTENT_TYPE"</span>]) : <span class="hljs-string">''</span>;


<span class="hljs-keyword">if</span> ($contentType !== <span class="hljs-string">'application/json'</span>) {
    http_response_code(<span class="hljs-number">415</span>);
    <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"Only JSON content is supported"</span>]);
    <span class="hljs-keyword">exit</span>();
}

$data = json_decode(file_get_contents(<span class="hljs-string">'php://input'</span>), <span class="hljs-literal">true</span>);

<span class="hljs-keyword">if</span> ($data === <span class="hljs-literal">null</span>) {
    http_response_code(<span class="hljs-number">400</span>);
    <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"Invalid JSON data"</span>]);
    <span class="hljs-keyword">exit</span>();
}


<span class="hljs-keyword">if</span> (!array_key_exists(<span class="hljs-string">'username'</span>, $data) || !array_key_exists(<span class="hljs-string">'password'</span>, $data)) {
    http_response_code(<span class="hljs-number">400</span>);
    <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"Missing login credentials"</span>]);
    <span class="hljs-keyword">exit</span>();
}

$user_gateway = <span class="hljs-keyword">new</span> UserGateway($database);

$user = $user_gateway-&gt;getByUsername($data[<span class="hljs-string">'username'</span>]);

<span class="hljs-keyword">if</span> ($user === <span class="hljs-literal">false</span>) {
    http_response_code(<span class="hljs-number">401</span>);
    <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"invalid authentication"</span>]);
    <span class="hljs-keyword">exit</span>;
}

<span class="hljs-keyword">if</span> (!password_verify($data[<span class="hljs-string">'password'</span>], $user[<span class="hljs-string">'password_hash'</span>])) {
    http_response_code(<span class="hljs-number">401</span>);
    <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"invalid authentication"</span>]);
    <span class="hljs-keyword">exit</span>;
}


<span class="hljs-keyword">require</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">"/tokens.php"</span>;

$refresh_token_gateway = <span class="hljs-keyword">new</span> RefreshTokenGateway($database, $_ENV[<span class="hljs-string">"SECRET_KEY"</span>]);

$refresh_token_gateway-&gt;create($refresh_token, $refresh_token_expiry);
</code></pre>
<p>Testing our login endpoint with the right parameters should result in the following response:</p>
<p><img src="https://miro.medium.com/v2/resize:fit:630/1*gSWQIGxsREf7xHoB0ZDpHQ.png" alt="Image" width="630" height="392" loading="lazy">
<em>endpoint testing</em></p>
<p>Note: Before we move on let us update our <code>Jwt</code> class, the <code>decode</code> function to be specific. The updated <code>decode</code> function in the <code>Jwt</code> class checks if a token has the correct format, ensuring it has a header, payload, and signature. It then verifies the token's signature to confirm it hasn't been tampered with. After that, it decodes the payload (containing user information and expiration time) from the token. Lastly, it checks if the token has expired, throwing an error if it has. Overall, these steps ensure the token is valid, unaltered, and within its expiration period for secure usage in the application.</p>
<p><code>Jwt</code> class:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Jwt</span>
</span>{

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> <span class="hljs-keyword">string</span> $key</span>)
    </span>{

    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">encode</span>(<span class="hljs-params"><span class="hljs-keyword">array</span> $payload</span>): <span class="hljs-title">string</span>
    </span>{

        $header = json_encode([
            <span class="hljs-string">"alg"</span> =&gt; <span class="hljs-string">"HS256"</span>,
            <span class="hljs-string">"typ"</span> =&gt; <span class="hljs-string">"JWT"</span>
        ]);

        $header = <span class="hljs-keyword">$this</span>-&gt;base64URLEncode($header);
        $payload = json_encode($payload);
        $payload = <span class="hljs-keyword">$this</span>-&gt;base64URLEncode($payload);

        $signature = hash_hmac(<span class="hljs-string">"sha256"</span>, $header . <span class="hljs-string">"."</span> . $payload, <span class="hljs-keyword">$this</span>-&gt;key, <span class="hljs-literal">true</span>);
        $signature = <span class="hljs-keyword">$this</span>-&gt;base64URLEncode($signature);
        <span class="hljs-keyword">return</span> $header . <span class="hljs-string">"."</span> . $payload . <span class="hljs-string">"."</span> . $signature;
    }



    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">decode</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $token</span>): <span class="hljs-title">array</span>
    </span>{
        <span class="hljs-keyword">if</span> (preg_match(<span class="hljs-string">"/^(?&lt;header&gt;.+)\.(?&lt;payload&gt;.+)\.(?&lt;signature&gt;.+)$/"</span>,
                   $token,
                   $matches) !== <span class="hljs-number">1</span>) {

            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">InvalidArgumentException</span>(<span class="hljs-string">"invalid token format"</span>);
        }

        $signature = hash_hmac(<span class="hljs-string">"sha256"</span>,
                               $matches[<span class="hljs-string">"header"</span>] . <span class="hljs-string">"."</span> . $matches[<span class="hljs-string">"payload"</span>],
                               <span class="hljs-keyword">$this</span>-&gt;key,
                               <span class="hljs-literal">true</span>);   

        $signature_from_token = <span class="hljs-keyword">$this</span>-&gt;base64urlDecode($matches[<span class="hljs-string">"signature"</span>]);

        <span class="hljs-keyword">if</span> ( ! hash_equals($signature, $signature_from_token)) {

            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> InvalidSignatureException;
        }

        $payload = json_decode(<span class="hljs-keyword">$this</span>-&gt;base64urlDecode($matches[<span class="hljs-string">"payload"</span>]), <span class="hljs-literal">true</span>);

        <span class="hljs-keyword">if</span> ($payload[<span class="hljs-string">"exp"</span>] &lt; time()) {

            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> TokenExpiredException;
        }

        <span class="hljs-keyword">return</span> $payload;
    }


    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">base64URLEncode</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $text</span>): <span class="hljs-title">string</span>
    </span>{

        <span class="hljs-keyword">return</span> str_replace([<span class="hljs-string">'+'</span>, <span class="hljs-string">'/'</span>, <span class="hljs-string">'='</span>], [<span class="hljs-string">'-'</span>, <span class="hljs-string">'_'</span>, <span class="hljs-string">''</span>], base64_encode($text));
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">base64URLDecode</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $text</span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> base64_decode(
            str_replace(
                [<span class="hljs-string">"-"</span>, <span class="hljs-string">"_"</span>],
                [<span class="hljs-string">"+"</span>, <span class="hljs-string">"/"</span>],
                $text
            )
        );
    }


}
</code></pre>
<p>Updated <strong>UserGateway.php</strong> class</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserGateway</span>
</span>{
    <span class="hljs-keyword">private</span> PDO $conn;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">Database $database</span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;conn = $database-&gt;getConnection();
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getByAPIKey</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $key</span>): <span class="hljs-title">array</span> | <span class="hljs-title">false</span>
    </span>{
        $sql = <span class="hljs-string">"SELECT *
                FROM user
                WHERE api_key = :api_key"</span>;

        $stmt = <span class="hljs-keyword">$this</span>-&gt;conn-&gt;prepare($sql);

        $stmt-&gt;bindValue(<span class="hljs-string">":api_key"</span>, $key, PDO::PARAM_STR);

        $stmt-&gt;execute();

        <span class="hljs-keyword">return</span> $stmt-&gt;fetch(PDO::FETCH_ASSOC);
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getByUsername</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $username</span>): <span class="hljs-title">array</span> | <span class="hljs-title">false</span>
    </span>{
        $sql = <span class="hljs-string">"SELECT *
                FROM user
                WHERE username = :username"</span>;

        $stmt = <span class="hljs-keyword">$this</span>-&gt;conn-&gt;prepare($sql);

        $stmt-&gt;bindValue(<span class="hljs-string">":username"</span>, $username, PDO::PARAM_STR);

        $stmt-&gt;execute();

        <span class="hljs-keyword">return</span> $stmt-&gt;fetch(PDO::FETCH_ASSOC);
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getByID</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> $id</span>): <span class="hljs-title">array</span> | <span class="hljs-title">false</span>
    </span>{
        $sql = <span class="hljs-string">"SELECT *
                FROM user
                WHERE id = :id"</span>;

        $stmt = <span class="hljs-keyword">$this</span>-&gt;conn-&gt;prepare($sql);

        $stmt-&gt;bindValue(<span class="hljs-string">":id"</span>, $id, PDO::PARAM_INT);

        $stmt-&gt;execute();

        <span class="hljs-keyword">return</span> $stmt-&gt;fetch(PDO::FETCH_ASSOC);
    }
}
</code></pre>
<p>Fnishing up with the ‘refresh’ endpoint:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-keyword">declare</span>(strict_types=<span class="hljs-number">1</span>);

<span class="hljs-keyword">require</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">"/bootstrap.php"</span>;

<span class="hljs-keyword">if</span> ($_SERVER[<span class="hljs-string">"REQUEST_METHOD"</span>] !== <span class="hljs-string">"POST"</span>) {

    http_response_code(<span class="hljs-number">405</span>);
    header(<span class="hljs-string">"Allow: POST"</span>);
    <span class="hljs-keyword">exit</span>;
}

$data = (<span class="hljs-keyword">array</span>) json_decode(file_get_contents(<span class="hljs-string">"php://input"</span>), <span class="hljs-literal">true</span>);

<span class="hljs-keyword">if</span> ( ! array_key_exists(<span class="hljs-string">"token"</span>, $data)) {

    http_response_code(<span class="hljs-number">400</span>);
    <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"missing token"</span>]);
    <span class="hljs-keyword">exit</span>;
}

$JwtController = <span class="hljs-keyword">new</span> Jwt($_ENV[<span class="hljs-string">"SECRET_KEY"</span>]);

<span class="hljs-keyword">try</span> {
    $payload = $JwtController-&gt;decode($data[<span class="hljs-string">"token"</span>]);

} <span class="hljs-keyword">catch</span> (<span class="hljs-built_in">Exception</span>) {

    http_response_code(<span class="hljs-number">400</span>);
    <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"invalid token"</span>]);
    <span class="hljs-keyword">exit</span>;
}

$user_id = $payload[<span class="hljs-string">"sub"</span>];


$refresh_token_gateway = <span class="hljs-keyword">new</span> RefreshTokenGateway($database, $_ENV[<span class="hljs-string">"SECRET_KEY"</span>]);

$refresh_token = $refresh_token_gateway-&gt;getByToken($data[<span class="hljs-string">"token"</span>]);

<span class="hljs-keyword">if</span> ($refresh_token === <span class="hljs-literal">false</span>) {

    http_response_code(<span class="hljs-number">400</span>);
    <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"invalid token (not on whitelist)"</span>]);
    <span class="hljs-keyword">exit</span>;
}

$user_gateway = <span class="hljs-keyword">new</span> UserGateway($database);

$user = $user_gateway-&gt;getByID($user_id);

<span class="hljs-keyword">if</span> ($user === <span class="hljs-literal">false</span>) {

    http_response_code(<span class="hljs-number">401</span>);
    <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">"message"</span> =&gt; <span class="hljs-string">"invalid authentication"</span>]);
    <span class="hljs-keyword">exit</span>;
}

<span class="hljs-keyword">require</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">"/tokens.php"</span>;

$refresh_token_gateway-&gt;delete($data[<span class="hljs-string">"token"</span>]);

$refresh_token_gateway-&gt;create($refresh_token, $refresh_token_expiry);
</code></pre>
<p>The code then proceeds to validate the HTTP request method, ensuring that only POST requests are accepted for sensitive operations like token handling. This validation is significant as it helps prevent unauthorized access and ensures the security of authentication processes.</p>
<p>Next, the code retrieves and decodes JSON data from the request body, specifically looking for a “token” key. This token is pivotal for authentication and access control within the application. If the token is missing, the code responds with an error message, highlighting the importance of including valid tokens for secure access.</p>
<p>The decoded token is then passed to the <code>JwtController</code> instance to decode its payload and validate its authenticity. This step is crucial as it verifies the integrity of the token and ensures that it hasn't been tampered with or forged.</p>
<p>Furthermore, the code interacts with a <code>RefreshTokenGateway</code> to manage refresh tokens, which play a vital role in generating access tokens securely. Refresh tokens provide a way to obtain new access tokens without requiring the user to log in again, enhancing user experience and maintaining continuous access to resources.</p>
<p>When a user logs in via the login endpoint, two crucial tokens are provided: an access token and a refresh token. The access token grants immediate access to resources, while the refresh token serves as a long-term authorization tool. If the access token expires, the refresh token is then passed to the refresh endpoint. This action triggers the generation of a new access token, which, in turn, creates a fresh refresh token. This process forms a robust and secure mechanism ensuring continuous access to resources while maintaining high levels of security and user convenience.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:630/1*FztaD8zQDrfY-nRdYQAbzA.png" alt="Image" width="630" height="369" loading="lazy">
<em>endpoint testing</em></p>
<p><img src="https://miro.medium.com/v2/resize:fit:630/1*tN5iW6surrwPWlwFD0iRLA.png" alt="Image" width="630" height="390" loading="lazy">
<em>endpoint testing</em></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In the analyzed code snippets and explanations regarding token management, authentication mechanisms, and refresh token usage within a web application, several key conclusions can be drawn.</p>
<p>Firstly, token-based authentication, especially using JSON Web Tokens, offer a secure and efficient way to handle user authentication and authorization processes. JWTs encapsulate user information in a compact format and are digitally signed, ensuring their integrity and authenticity.</p>
<p>Secondly, the implementation of access tokens and refresh tokens enhances security and user experience. Access tokens provide immediate access to resources and have a short lifespan, promoting security by limiting their usability in case of unauthorized access. On the other hand, refresh tokens have a longer lifespan and enable users to obtain new access tokens without repeated authentication, thereby improving user convenience.</p>
<p>Furthermore, strict typing enforcement, proper validation of HTTP request methods, and token format checks are crucial elements in ensuring the robustness and reliability of token-based authentication systems. These practices help prevent common vulnerabilities such as unauthorized access attempts, token tampering, and invalid token usage.</p>
<p>Overall, by combining secure token management practices, effective authentication mechanisms, and adherence to coding best practices, web applications can achieve a high level of security, user-friendliness, and resilience against potential threats.</p>
<p>See the full code <a target="_blank" href="https://github.com/Oghenekparobo/php_auth_jwt_tut/tree/refresh-token">here</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Implement Relationship Based Access Control (ReBAC) ]]>
                </title>
                <description>
                    <![CDATA[ By Imran In today's digital age, managing who can access what resources is more critical than ever. That's where ReBAC comes in. It's a fresh take on authorization, focusing on the relationships between different entities rather than just assigning s... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/implement-relationship-based-access-control/</link>
                <guid isPermaLink="false">66d45f31246e57ac83a2c76f</guid>
                
                    <category>
                        <![CDATA[ authorization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 08 Mar 2024 14:08:21 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/03/RELATIONSHIP-BASED-ACCESS-CONTROL.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Imran</p>
<p>In today's digital age, managing who can access what resources is more critical than ever. That's where ReBAC comes in. It's a fresh take on authorization, focusing on the relationships between different entities rather than just assigning static roles or attributes.</p>
<p>Traditional access control methods, like Role-Based Access Control (RBAC), assign specific roles to users. While this works in many cases, it can become difficult, especially in dynamic environments where roles and permissions need to adapt quickly. On the other hand, Attribute-Based Access Control (ABAC) offers flexibility based on user attributes, but it can get complex to manage.</p>
<p>Now, ReBAC is all about understanding the intricate web of relationships between entities. Whether it's within an organization, a social media platform, or a project management tool, ReBAC ensures that access control remains dynamic and context-aware.</p>
<p>By the end of this tutorial, you'll have a clear understanding of ReBAC and be able to model a ReBAC scenario.</p>
<h2 id="heading-key-takeaways">Key Takeaways</h2>
<ul>
<li><strong>ReBAC Principles:</strong> Understand how ReBAC uses relationships between entities for access control, differing from traditional models.</li>
<li><strong>Policy Visualization:</strong> Learn about representing policies as graphs for clearer management.</li>
<li><strong>Real-World Examples:</strong> Explore ReBAC's application in scenarios like social media platforms and project management tools.</li>
<li><strong>Benefits of ReBAC:</strong> Discover the advantages like granular control and dynamic policy adaptation.</li>
<li><strong>Permission Models:</strong> Get familiar with ReBAC's common models such as Ownership and Hierarchical Models.</li>
<li><strong>Permify Implementation:</strong> Step-by-step guide to implement ReBAC in Permify, including entity definition, relationship establishment, and permissions setup.</li>
</ul>
<h2 id="heading-what-is-relationship-based-access-control-rebac">What is Relationship-Based Access Control (ReBAC)?</h2>
<p>Traditional access control methods, like Role-Based Access Control (RBAC), assign specific roles to users, like giving someone a badge that says "manager" or "employee". But what if the roles aren't so clear-cut, and relationships between people and resources matter more?</p>
<p>That's where Relationship-Based Access Control (ReBAC) steps in. Instead of relying solely on predefined roles or attributes, ReBAC considers the intricate web of connections between users, resources, and other entities. It's like saying, "You can access this because you're connected to it in this specific way", rather than just based on a generic label.</p>
<p>But how does ReBAC actually do this? ReBAC examines the relationships between entities, such as users and resources, and uses these connections to determine access.</p>
<p>Let's break it down further. In our everyday lives, we have relationships that matter. Think about social media – you can see certain posts because you're friends with someone or because someone you follow liked it. ReBAC takes this idea and applies it to access control in systems.</p>
<h2 id="heading-policy-as-a-graph">Policy as a Graph</h2>
<p>At the core of ReBAC lies the concept of "Policy as a Graph". This idea shows the importance of visualizing access policies through relationships.</p>
<p>Imagine that you have a detailed map of a bustling city. It doesn't just show buildings but also the connections between them – the roads, bridges, and pathways that link everything together.</p>
<p>Now, picture this map as a representation of your organization. Instead of buildings, it represents team members, departments, and their roles. The connections between them symbolize the relationships that dictate access.</p>
<p>This is what we mean by "Policy as a Graph" in ReBAC.</p>
<p>In simpler terms, access policies are like interconnected dots on a graph. Each dot represents an entity, and the lines between them signify the relationships influencing authorization. It's a visual representation that helps us understand the complex web of connections that govern access.</p>
<h2 id="heading-how-is-rebac-different-from-other-control-models">How is ReBAC Different from Other Control Models?</h2>
<p>Now, let's explore how ReBAC sets itself apart from other access control models, such as Role-Based Access Control (RBAC).</p>
<p>Unlike traditional models, ReBAC doesn't rely solely on rigid roles or attributes. Instead, it works on deriving permissions from existing relationships. Here's how it stands out:</p>
<ul>
<li><strong>Role Derivation:</strong>ReBAC allows the creation of authorization policies based on pre-existing relationships. This means that assigning a user a certain role in one context might automatically extend that role to related entities, saving the need for manual assignment.</li>
<li><strong>Resource Roles:</strong>Unlike global roles in traditional models, ReBAC introduces the concept of resource-specific roles (for example: Folder#Owner). These roles are exclusive to the context of a particular resource, ensuring that permissions are relevant and tailored to that specific entity.</li>
</ul>
<h2 id="heading-real-world-examples">Real-World Examples</h2>
<p>To better understand how Relationship-Based Access Control (ReBAC) functions in the real world, let's explore two scenarios that mimic everyday complexities.</p>
<p>These examples will help illustrate how ReBAC excels in managing intricate access dynamics.</p>
<h3 id="heading-instagram-like-social-platform">Instagram-like Social Platform</h3>
<p>Consider an Instagram-inspired platform where users hold individual accounts. Each account consists of user-generated content, namely pictures (Pic 1 and Pic 2), chat interactions with different users, and project collaboration.</p>
<p>The user account possesses a list of blocked users who are restricted from viewing pictures. Here's a detailed breakdown of the entities and permissions:</p>
<h4 id="heading-1-account-entities">1. Account Entities</h4>
<ul>
<li><strong>User Account:</strong> Represents individual user accounts on the platform.</li>
<li><strong>Pictures (Pic 1 and Pic 2):</strong> Depict user-generated visual content.</li>
<li><strong>Chats:</strong> Captures interaction histories with different users.</li>
<li><strong>Blocked Users List:</strong> Maintains a list of users who are blocked from viewing pictures.</li>
</ul>
<h4 id="heading-2-permissions-dynamics">2. Permissions Dynamics</h4>
<h5 id="heading-account-access-permissions">Account Access Permissions:</h5>
<ul>
<li>"Account#Owner" grants ownership, allowing the user account holder to manage all aspects.</li>
<li>"Account#Viewer" enables others to view the user's account.</li>
</ul>
<h5 id="heading-picture-management-permissions">Picture Management Permissions:</h5>
<ul>
<li>"Picture#Owner" designates ownership at the picture level, allowing the user to edit, delete, and upload pictures.</li>
<li>"Picture#Viewer" permits normal viewers to only view pictures.</li>
<li>"BlockedUser#CannotView" ensures that blocked users cannot view pictures.</li>
</ul>
<h5 id="heading-chat-interaction-permissions">Chat Interaction Permissions:</h5>
<ul>
<li>"Chat#Participant" allows users to participate in chat interactions.</li>
<li>"Chat#BlockedUser" restricts certain users from participating in chats.</li>
</ul>
<h5 id="heading-account-editing-permissions">Account Editing Permissions:</h5>
<ul>
<li>"Account#Edit" grants the ability to update account details and preferences.</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Instagram.png" alt="Instagram.png" width="600" height="400" loading="lazy">
<em>Instagram-like Social Platform Entities</em></p>
<p>In this scenario, the "#" symbol represents the relationship between entities when defining permissions. For example, "Account#Owner" signifies ownership of the user account, allowing the account holder to manage all aspects of their account.</p>
<h3 id="heading-project-management-tool">Project Management Tool</h3>
<p>Imagine a project management tool where teams collaborate on various projects. Entities like "Teams", "Projects", and "Tasks" play central roles, showcasing ReBAC's adaptability:</p>
<h4 id="heading-1-team-entities">1. Team Entities:</h4>
<ul>
<li><strong>Teams:</strong> Represent collaborative groups within the project management tool.</li>
<li><strong>Projects:</strong> Encompass various ongoing initiatives.</li>
<li><strong>Tasks:</strong> Break down project activities into manageable tasks.</li>
</ul>
<h4 id="heading-2-permissions-dynamics-1">2. Permissions Dynamics:</h4>
<h5 id="heading-team-leadership-permissions">Team Leadership Permissions:</h5>
<ul>
<li>"Team#Lead" designates team leadership, allowing leaders to manage team-related activities.</li>
</ul>
<h5 id="heading-project-ownership-permissions">Project Ownership Permissions:</h5>
<ul>
<li>"Project#Owner" signifies ownership at the project level, granting comprehensive control over project-related actions.</li>
</ul>
<p><strong>Task Assignment Permissions:</strong></p>
<ul>
<li>"Task#Assignee" designates individuals responsible for specific tasks.</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/project.png" alt="project.png" width="600" height="400" loading="lazy">
<em>Project Management Tool Entities</em></p>
<p>These real-world scenarios demonstrate ReBAC's versatility and effectiveness in managing access control in different settings.</p>
<h2 id="heading-advantages-of-rebac">Advantages of ReBAC</h2>
<p>Now, let's understand why Relationship-Based Access Control (ReBAC) stands out from traditional methods like Role-Based Access Control (RBAC) and Attribute-Based Access Control (ABAC). ReBAC brings a host of benefits to the table, enhancing scalability, flexibility, and adaptability in complex organizational setups. Let's take a closer look at its key advantages:</p>
<h3 id="heading-granular-and-contextual-control">Granular and Contextual Control</h3>
<p>ReBAC allows organizations to define granular access controls tailored to the specific relationships between users, resources, and entities. This ensures that permissions are contextually relevant, providing a nuanced level of control.</p>
<h3 id="heading-efficient-management-of-hierarchies">Efficient Management of Hierarchies</h3>
<p>In scenarios with hierarchical structures, ReBAC simplifies the management of access control. By allowing permissions to be inherited based on relationships, it reduces the need for manual role assignments. </p>
<p>This simplifies the creation of natural connections between different business units, resources, and entities, making it easier to navigate complex hierarchies.</p>
<h3 id="heading-scalability-and-adaptability">Scalability and Adaptability</h3>
<p>ReBAC is designed to scale with organizational growth and changes in relationships. It easily accommodates the introduction of new entities or connections. However, it's crucial to address the challenge of role explosion, where the number of roles grows exponentially alongside asset growth. </p>
<p>Without proper management, this can lead to security risks and administrative overhead. Yet, ReBAC's scalability ensures that access controls remain effective, mitigating these challenges and avoiding the need for extensive modifications.</p>
<p>With these advantages in mind, ReBAC offers a robust framework for access control that meets the evolving needs of modern organizations. Now, let's delve into the common Relationship Type Permission Models to further understand how ReBAC operates.</p>
<h2 id="heading-common-relationship-type-permission-models">Common Relationship Type Permission Models</h2>
<p>Let’s look at the some of the permission models:</p>
<h3 id="heading-ownership-model"><strong>Owners</strong>hip Model</h3>
<p>The Ownership Model in ReBAC is a fundamental concept where ownership relationships streamline authorization within hierarchical structures.</p>
<p>In this model, the act of owning a higher-level entity automatically extends ownership over its subordinate entities.</p>
<p>Imagine a scenario in a cloud storage platform where users create folders to organize their files. In the Ownership Model, the user who creates a folder is designated as the owner.</p>
<p>Consequently, this ownership relation automatically grants the user ownership permissions for all files within that folder.</p>
<p>This hierarchical ownership structure simplifies permission management and mirrors real-world ownership dynamics.</p>
<h3 id="heading-parent-child-amp-hierarchical-model"><strong>Parent-Child &amp; Hierarc</strong>hical Model</h3>
<p>The Parent-Child &amp; Hierarchical Model is a powerful tool for managing access control in hierarchical structures such as organizational frameworks or file systems.</p>
<p>In this model, permissions granted at the parent level down to its child entities, ensuring a cohesive and efficient authorization system.</p>
<p>Consider a corporate environment where organizations have multiple departments. Using ReBAC's Parent-Child &amp; Hierarchical Model, permissions granted at the organization level, such as admin privileges, seamlessly extend to the organization's departments and their respective members.</p>
<p>This hierarchical flow of permissions reflects the organizational structure, making it easy to manage access control across different levels.</p>
<h3 id="heading-user-groups-amp-teams-model">User Groups &amp; Teams Model</h3>
<p>The User Groups &amp; Teams Model allows for efficient permission management by grouping users based on shared attributes or project affiliations.</p>
<p>In this model, permissions assigned to a group leader, for instance, can be effortlessly applied to all members of that group.</p>
<p>In a collaborative project management tool, teams serve as user groups. Applying ReBAC's User Groups &amp; Teams Model, the team lead's permissions, like editing or deleting project tasks, can be automatically inherited by all team members.</p>
<p>This streamlined approach simplifies access control in collaborative environments, where team-based permissions are crucial for project efficiency.</p>
<p>These three Relationship-Based Access Control models demonstrate the flexibility and adaptability of ReBAC in handling diverse organizational structures and application domains.</p>
<p>By aligning permissions with inherent relationships among entities, ReBAC provides an intuitive and powerful access control framework.</p>
<h2 id="heading-how-to-implement-rebac-with-permify">How to Implement ReBAC with Permify</h2>
<p>Now, let's practically implement ReBAC using Permify.</p>
<p><a target="_blank" href="https://permify.co/">Permify</a> is an open-source authorization as a service platform that allows developers to model, manage, and enforce access control in applications. It provides tools for defining complex authorization rules and relationships between entities, such as users, organizations, and resources.</p>
<p>Permify uses a domain-specific language for creating authorization models and offers a Playground environment for testing these models.</p>
<p>It also supports the creation of relational tuples and attributes for managing dynamic access control scenarios, streamlining the process of implementing robust and flexible authorization systems in software applications.</p>
<p>We'll create a scenario covering both Ownership and Parent-Child &amp; Hierarchical models.</p>
<p>We'll use the <a target="_blank" href="https://play.permify.co/">Permify Playground</a> for modeling.</p>
<h3 id="heading-modeling">Modeling</h3>
<p>Modeling in Permify involves creating a schema that defines the relationships and permissions between different entities in your system. </p>
<p>Here's a simplified process:</p>
<ol>
<li><strong>Define Entities</strong>: Start by creating entities that represent the resources in your system (for example: users, organizations, teams).</li>
<li><strong>Define Relations</strong>: Establish relationships between these entities. For example, an organization can have members and admins, or a team can be part of an organization.</li>
<li><strong>Define Actions and Permissions</strong>: Specify the actions that can be performed on each entity and the conditions under which they are allowed. For example, only admins can delete an organization.</li>
</ol>
<p>Permify uses its own language for modeling authorization logic, allowing for complex structures using set-algebraic operators. The modeling process includes defining entities, relations, actions, permissions, and, if needed, attributes for more advanced scenarios like ABAC (Attribute-Based Access Control).</p>
<p>Modeling in Permify is about creating a clear blueprint of your organization's structure and defining who gets to do what. </p>
<p>Let's break down how to model a schema in Permify.</p>
<h3 id="heading-step-1-define-entities">Step 1: Define Entities</h3>
<p>Entities are the core objects in your model. In this case, we have <code>user</code>, <code>organization</code>, <code>department</code>, <code>project</code>, <code>file</code>, and <code>task</code>.</p>
<pre><code class="lang-jsx">entity user {}
entity organization {}
entity department {}
entity project {}
entity file {}
entity task {}
</code></pre>
<h3 id="heading-step-2-establish-relationships">Step 2: Establish Relationships</h3>
<p>Next, we specify relationships between these entities. This defines how they are connected.</p>
<p><strong>Organization</strong>:</p>
<ul>
<li>Has <code>admin</code> who are users.</li>
</ul>
<pre><code class="lang-jsx">entity organization {
    relation admin @user
}
</code></pre>
<p><strong>Department</strong>:</p>
<ul>
<li>Belongs to an <code>organization</code> (parent).</li>
<li>Has <code>head</code>, <code>manager</code>, and <code>employee</code> roles, all of which are users.</li>
</ul>
<pre><code class="lang-jsx">entity department {
    relation parent @organization
    relation head @user
    relation manager @user
    relation employee @user
}
</code></pre>
<p><strong>Project</strong>:</p>
<ul>
<li>Belongs to a <code>department</code> (parent).</li>
</ul>
<pre><code class="lang-jsx">entity project {
    relation parent @department
}
</code></pre>
<p><strong>File</strong>:</p>
<ul>
<li>Belongs to a <code>department</code> (parent).</li>
<li>Has an <code>owner</code> who is a user.</li>
</ul>
<pre><code class="lang-jsx">entity file {
    relation parent @department
    relation owner @user
}
</code></pre>
<p><strong>Task</strong>:</p>
<ul>
<li>Belongs to a <code>project</code> (parent).</li>
<li>Has an <code>assignee</code> who is a user.</li>
</ul>
<pre><code class="lang-jsx">entity task {
    relation parent @project
    relation assignee @user
}
</code></pre>
<h3 id="heading-step-3-define-permissions">Step 3: Define Permissions</h3>
<p>Permissions determine what actions specific roles can perform on each entity.</p>
<p><strong>Project</strong>:</p>
<ul>
<li><code>contribute_to_project</code> permission is granted to <code>employee</code> or <code>manager</code> of the parent <code>department</code>.</li>
</ul>
<pre><code class="lang-jsx">entity project {
    <span class="hljs-comment">// ... (existing relations)</span>
    permission contribute_to_project = parent.employee or parent.manager
}
</code></pre>
<p><strong>File</strong>:</p>
<ul>
<li><code>read</code>, <code>edit</code>, and <code>delete</code> permissions are controlled based on the <code>manager</code> of the parent <code>department</code> and the <code>owner</code>.</li>
</ul>
<pre><code class="lang-jsx">entity file {
    <span class="hljs-comment">// ... (existing relations)</span>
    permission read   = parent.manager or owner
    permission edit   = parent.manager or owner
    permission <span class="hljs-keyword">delete</span> = owner
}
</code></pre>
<p><strong>Task</strong>:</p>
<ul>
<li><code>view_task</code> permission is given to the <code>assignee</code>.</li>
</ul>
<pre><code class="lang-jsx">entity task {
    <span class="hljs-comment">// ... (existing relations)</span>
    permission view_task = assignee
}
</code></pre>
<p><strong>Full Schema:</strong></p>
<pre><code><span class="hljs-comment">// Define entities</span>
entity user {}

entity organization {
    <span class="hljs-comment">// Organizational roles</span>
    relation admin @user
}

entity department {
    <span class="hljs-comment">// Department roles</span>
    relation parent @organization
    relation head @user
    relation manager @user
    relation employee @user
}

entity project {
    <span class="hljs-comment">// Project roles</span>
    relation parent @department

    <span class="hljs-comment">// Permissions</span>
    permission contribute_to_project = parent.employee or parent.manager
}

entity file {
    <span class="hljs-comment">// Represents files' parent entity (department)</span>
    relation parent @department

    <span class="hljs-comment">// Represents the owner of the file</span>
    relation owner @user

    <span class="hljs-comment">// Permissions</span>
    permission read   = parent.manager or owner
    permission edit   = parent.manager or owner
    permission <span class="hljs-keyword">delete</span> = owner
}

entity task {
    <span class="hljs-comment">// Represents tasks' parent entity (project)</span>
    relation parent @project

    <span class="hljs-comment">// Represents the assignee of the task</span>
    relation assignee @user

    <span class="hljs-comment">// Permissions</span>
    permission view_task   = assignee
}
</code></pre><h3 id="heading-relation-tuples">Relation Tuples</h3>
<p>The creation of relation tuples for the organization schema can be accomplished through the Permify Playground and API. </p>
<p>Here's how the relationship tuples would be structured according to the schema:</p>
<h4 id="heading-user-and-organization-relationships">User and Organization Relationships:</h4>
<ul>
<li>For assigning a user as an admin in an organization, the tuple would be: <code>organization:ID#admin@user:ID</code>.</li>
<li>To denote a user as a member of an organization: <code>organization:ID#member@user:ID</code>.</li>
</ul>
<h4 id="heading-user-and-department-relationships">User and Department Relationships:</h4>
<ul>
<li>Assigning a head to a department: <code>department:ID#head@user:ID</code>.</li>
<li>Assigning a manager to a department: <code>department:ID#manager@user:ID</code>.</li>
<li>Associating an employee with a department: <code>department:ID#employee@user:ID</code>.</li>
<li>To set a department's parent organization: <code>department:ID#parent@organization:ID</code>.</li>
</ul>
<h4 id="heading-project-and-department-relationships">Project and Department Relationships:</h4>
<ul>
<li>To define the parent department of a project: <code>project:ID#parent@department:ID</code>.</li>
</ul>
<h4 id="heading-file-management">File Management:</h4>
<ul>
<li>Associating a file with its parent department: <code>file:ID#parent@department:ID</code>.</li>
<li>Defining the owner of a file: <code>file:ID#owner@user:ID</code>.</li>
</ul>
<h4 id="heading-task-management">Task Management:</h4>
<ul>
<li>Linking a task to its parent project: <code>task:ID#parent@project:ID</code>.</li>
<li>Assigning a user as the assignee of a task: <code>task:ID#assignee@user:ID</code>.</li>
</ul>
<p>In each of these tuples, <code>ID</code> is a placeholder that should be replaced with the actual identifier of the entity or user in your system. </p>
<p>For instance, if you have an organization with an ID of 1 and a user with an ID of 3, and you want to assign this user as an admin of that organization, the tuple would be <code>organization:1#admin@user:3</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Untitled-2.png" alt="Untitled" width="600" height="400" loading="lazy">
<em>Relationships dashboard</em></p>
<p>These tuples are created and managed using the Permify API. The API allows for creating, updating, and deleting these tuples as needed, reflecting the dynamic nature of relationships and permissions in an organization. This flexibility ensures that your authorization data is always up-to-date and consistent with the current state of your system's entities and their relationships.</p>
<h3 id="heading-enforcement">Enforcement</h3>
<p>To enforce access control in your schema using Permify, you can create scenarios in the Permify Playground's Enforcement section. This is done using YAML to define various test scenarios. </p>
<p>Here's an example based on your schema and the created relation tuples:</p>
<h4 id="heading-check-if-a-user-for-example-user2-can-contribute-to-a-project">Check if a user (for example: user:2) can contribute to a project:</h4>
<ul>
<li>Entity: <code>project:1</code></li>
<li>Subject: <code>user:2</code></li>
<li>Assertion: <code>contribute_to_project: true or false</code> (depending on whether user:2 is an employee or manager in the parent department of project:1).</li>
</ul>
<pre><code>- name: user_access_test
  <span class="hljs-attr">checks</span>:
    - entity: project:<span class="hljs-number">1</span>
      <span class="hljs-attr">subject</span>: user:<span class="hljs-number">2</span>
      <span class="hljs-attr">context</span>: <span class="hljs-literal">null</span>
      <span class="hljs-attr">assertions</span>:
        contribute_to_project: <span class="hljs-literal">false</span>
  <span class="hljs-attr">entity_filters</span>: []
  <span class="hljs-attr">subject_filters</span>: []
</code></pre><p><strong>Check if a user (for example: user:4) can view a task</strong>:</p>
<ul>
<li>Entity: <code>task:1</code></li>
<li>Subject: <code>user:4</code></li>
<li>Assertion: <code>view_task: true or false</code> (true if user:4 is the assignee of the task).</li>
</ul>
<pre><code>- name: user_access_test
  <span class="hljs-attr">checks</span>:
    - entity: task:<span class="hljs-number">1</span>
      <span class="hljs-attr">subject</span>: user:<span class="hljs-number">4</span>
      <span class="hljs-attr">context</span>: <span class="hljs-literal">null</span>
      <span class="hljs-attr">assertions</span>:
        view_task: <span class="hljs-literal">false</span>
  <span class="hljs-attr">entity_filters</span>: []
  <span class="hljs-attr">subject_filters</span>: []
</code></pre><p>These scenarios will help you validate the permissions as per your schema in a controlled environment. </p>
<p>Each assertion in the YAML scenario will define the expected outcome (true or false) for a particular action or permission based on your schema and data tuples.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Untitled-1.png" alt="Untitled" width="600" height="400" loading="lazy">
<em>YAML representation</em></p>
<p>For detailed steps and examples, refer to the <a target="_blank" href="https://docs.permify.co/docs/getting-started/modeling/">Permify Modeling Documentation</a>.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>By following these steps, you can effectively implement a sophisticated ReBAC system using Permify. </p>
<p>This implementation will provide a robust, flexible, and secure access control framework tailored to the unique needs and relationships within your organization.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Set Up Authentication in Your Apps with Supabase Auth ]]>
                </title>
                <description>
                    <![CDATA[ In this article, you'll learn the basic key concepts that'll help you grasp how authentication and authorization work.  You'll start by learning what authentication and authorization are, and then learn how to implement authentication in your applica... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/set-up-authentication-in-apps-with-supabase/</link>
                <guid isPermaLink="false">66b999acd9d170feecefbbc7</guid>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ authorization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ supabase ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Fatuma Abdullahi ]]>
                </dc:creator>
                <pubDate>Mon, 29 Jan 2024 10:53:38 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/01/Group-3--9-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this article, you'll learn the basic key concepts that'll help you grasp how authentication and authorization work. </p>
<p>You'll start by learning what authentication and authorization are, and then learn how to implement authentication in your applications using Supabase auth.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
    <li>
        <a href="#prerequisites">
            Prerequisites
        </a>
    </li>
    <li>
        <a href="#what-is-authentication-and-authorization">
            What Is Authentication and Authorization?
        </a>
    </li>
    <li>
        <a href="#how-does-authentication-work">
            How Does Authentication Work?
        </a>
    </li>
    <li>
        <a href="#session-management-with-tokens-secrets-and-cookies">
            Session Management with Tokens, Secrets, and Cookies
        </a>
    </li>
    <li>
        <a href="#types-of-authentication-factors">
            Types of Authentication Factors
        </a>
    </li>
    <li>
        <a href="#common-authentication-strategies">
            Common Authentication Strategies
        </a>
        <ul>
            <li>
                <a href="#password-based-authentication">
                     Password-based Authentication
                </a>
            </li>
            <li>
                <a href="#password-less-authentication">
                     Password-less Authentication
                </a>
            </li>
            <li>
                <a href="#two-factor-authentication-2fa-">
                     Two-Factor Authentication (2FA)
                </a>
            </li>
            <li>
                <a href="#multi-factor-authentication-mfa-">
                     Multi-Factor Authentication (MFA)
                </a>
            </li>
              <li>
                <a href="#oauth-2-0-and-social-authentication">
                    OAuth 2.0 and Social Authentication
                </a>
            </li>
              <li>
                <a href="#sso-and-saml">
                    SSO and SAML
                </a>
            </li>
        </ul>
    </li>
    <li>
        <a href="#authentication-and-security">
            Authentication and Security
        </a>
    </li>
    <li>
        <a href="#supabase-and-supabase-authentication-service">
            Supabase and Supabase Authentication Service
        </a>
    </li>
    <li>
        <a href="#how-to-use-supabase-auth">
            How to use Supabase Auth
        </a>
        <ul>
            <li>
                <a href="#the-api">
                    The API
                </a>
            </li>
            <li>
                <a href="#sdks">
                    SDKs
                </a>
            </li>
            <li>
                <a href="#auth-ui-helpers">
                    Auth UI Helpers
                </a>
            </li>
        </ul>

<p>    </p></li>
     <li>
         <a href="#summary">
             Summary
         </a>
    </li>
    <li>
        <a href="#resources">
            Resources
        </a>
    </li>
</ul><p></p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>You'll need the following to make the most out of this article:</p>
<ul>
<li>Basic programming knowledge.</li>
<li><a target="_blank" href="https://supabase.com/">A Supabase project</a> to follow along.</li>
<li>And a text editor to try out the example code snippets.</li>
</ul>
<h2 id="heading-what-is-authentication-and-authorization">What Is Authentication and Authorization?</h2>
<p>In simple terms, authentication is the process of a user identifying themselves to a system and the system confirming that the user is who they claim to be.   </p>
<p>On the other hand, authorization is the process of the system determining which parts of the application the user is allowed to view or interact with, and which parts the user is not allowed to access. </p>
<h2 id="heading-how-does-authentication-work">How Does Authentication Work?</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/image-135.png" alt="Image" width="600" height="400" loading="lazy">
<em>A flowchart depicting the user authentication process</em></p>
<p>The first time a user interacts with a system, they will be requested to register. Typically, the user will provide a piece of information and a secret that is meant to be known only by them and the system. This is the registration part of the authentication process.</p>
<p>The next time the user interacts with the same system, they will be required to provide the identifying information along with the previously defined secret in order to verify their identity. </p>
<p>The device the user initiates the interaction from is the client and the system is the server. Once the system verifies the user, it sends over some information to the client about the user. </p>
<p>Because this process takes time and requires some action from the user, the client will store this information and send it back to the system whenever the user needs to access the system. This reduces friction by not requiring the user to actively re-authenticate every single time. This creates a user session.</p>
<h2 id="heading-session-management-with-tokens-secrets-and-cookies">Session Management with Tokens, Secrets, and Cookies</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/image-136.png" alt="Image" width="600" height="400" loading="lazy">
<em>A sequence diagram showing session management in a client-server architecture</em></p>
<p>The server can pass the user's information to the client in two ways – through tokens or session ids.</p>
<p>In the case of tokens, the server generates a signed token and passes it to the client. This token is typically a JWT and may contain information regarding the user. The client will store this token and send it back to the server every time the user makes a request. </p>
<p>The server is able to verify the integrity of the token because it signed it. This is referred to as stateless authentication because the token is self contained and the server does not need to store session data in a database or cache. </p>
<p>In the case of cookies, the server creates a record of the user session in a database or a cache that will include a session ID. The server send this session ID to the client.</p>
<p>The client stores this session ID in a cookie and sends it back to the server whenever the user makes a request. The session ID is a random string that acts as pointer to the actual user record in the database. </p>
<p>When the server receives this cookie, it matches the session ID it contains to its session records, and then matches that record to the user data in the database. This is referred to as stateful authentication because a database look-up is needed.</p>
<h2 id="heading-types-of-authentication-factors">Types of Authentication Factors</h2>
<p>An authentication factor refers to a type of credential that can be used to verify a user's identity. There are 3 factors typically used in the authentication process, and they are:</p>
<ol>
<li>Something you know: an examples is a password.</li>
<li>Something you have: an example is a token sent to your phone.</li>
<li>Something you are: an example is your fingerprint.</li>
</ol>
<h2 id="heading-common-authentication-strategies">Common Authentication Strategies</h2>
<p>Authentication strategies refer to the processes used to verify a user. Different types of authentication strategies include:</p>
<h3 id="heading-password-based-authentication">Password-based Authentication</h3>
<p>This refers to the traditional way of users identifying themselves by providing a text-based secret that is user defined. Typically, the system handles the entire process on its servers and is responsible for security and reliability.</p>
<h3 id="heading-password-less-authentication">Password-less Authentication</h3>
<p>In this approach, the system verifies the user’s identity without requiring user defined passwords. The system will, instead, generate a one time password (OTP) and send to the user. This OTP is then used in place of a password to gain access to the system. Examples include magic links, where the system sends a code to the user’s email.</p>
<h3 id="heading-two-factor-authentication-2fa">Two-Factor Authentication (2FA)</h3>
<p>The system attempts to verify the user is who they claim to be by requiring an extra piece of information after the primary authentication has checked out. </p>
<p>This can be an OTP sent to the user via email or SMS, or it can be by requiring the users' biometric information before the system grants access.</p>
<h3 id="heading-multi-factor-authentication-mfa">Multi-Factor Authentication (MFA)</h3>
<p>This is similar to 2FA, except that the system will use more than one extra method to verify the user’s identity. The extra methods or factors used in both MFA and 2FA are usually external to the system, such as an SMS requiring a phone.</p>
<h3 id="heading-oauth-20-and-social-authentication">OAuth 2.0 and Social Authentication</h3>
<p>OAuth is an authorization framework that allows clients to access information from an external server on the user's behalf. The external server prompts the user for permission to share the requested resources with the client. </p>
<p>After user permits the action, the external server issues an access token to the client. </p>
<p>The client then gives this access token to the original server, which verifies the token's validity and manages access to the requested resources. OAuth 2.0 is the latest version of OAuth and is the more widely used framework. </p>
<p>OAuth 2.0 extends support for non-browser based systems. Social Authentication is based on OAuth 2.0 but in this case, the external server that the client redirects the user to is typically a social media platform. This is the type of authentication process carried out whenever you see a "Continue with Twitter/X" button on an authentication page. </p>
<h3 id="heading-sso-and-saml">SSO and SAML</h3>
<p>SAML stands for Security Assertion Markup Language. It is a standard for passing authentication and authorization information between systems. One system acts as the requesting system or the service provider (SP) and the other system holds the requested information or acts as the Identity Provider (IdP). </p>
<p>On receiving this request, the identity provider will generate some statements in SAML form that contains some user information. The service provider then uses this information to decide how to handle the user in relation with its protected resources. </p>
<p>SSO refers to Single Sign On. This is an authentication strategy that lets users sign in through one system/application that then lets them access multiple applications within the same network. </p>
<p>This improves the user experience by not requiring the user to log in to different related applications. An example of this is Google workspace. You don't need to log into Docs separately if you are already logged into your Gmail account. SSO is facilitated by SAML as SAML provides a standard authentication mechanism and allows different systems to trust each other. </p>
<h2 id="heading-authentication-and-security">Authentication and Security</h2>
<p>Authentication involves handling, moving, and storing sensitive user information in relation to protected server resources. This makes security and best practices an important aspect of an authentication system.</p>
<p>There are some basic steps you can take to greatly increase the security of your authentication systems. These include:</p>
<ul>
<li>Enforcing stronger passwords.</li>
<li>Requiring the user to register an extra factor to enable 2FA.</li>
<li>Encrypting sensitive data as it is being transferred via HTTPS.</li>
<li>Storing passwords in an encrypted manner.</li>
<li>Using standard authentication frameworks like OAuth 2.0.</li>
</ul>
<p>There are certain compliances that your system should consider when handling sensitive user data beyond specific authentication information. This is even more so if operating in certain countries or handling enterprise applications. These compliances include:</p>
<ul>
<li><strong>GDPR</strong>: This compliance enforces standards around data handling including confidentiality and integrity.</li>
<li><strong>HIPAA</strong>: This compliance applies to medical data. It expects high levels of integrity.</li>
<li><strong>SOC</strong>: This is a framework more generally required of cloud technologies. It is based on the American Institute of CPAs and covers aspects of privacy, security, availability, integrity and confidentiality.</li>
</ul>
<p>Keeping all this in mind, you will find that it is often easier to use dedicated authentication services for your applications instead of rolling out your own auth.</p>
<p>There are lots of options for this, including dedicated authentication services such as Clerk and Auth0, and Backend-as-a-Service such as Supabase and Firebase. In this case, let's take a look at the Supabase authentication offering.</p>
<h2 id="heading-supabase-and-supabase-authentication-service">Supabase and Supabase Authentication Service</h2>
<p>Supabase is an open source Backend as a Service (BaaS) platform that makes developing a backend for your applications very easy and fast. It is based on open source technologies and actively supports the open source ecosystem. </p>
<p>Supabase offers common services that most backend applications will require. These services are:</p>
<ul>
<li>Database: This is a fully featured Postgres database.</li>
<li>Authentication: This is an enterprise ready authentication service that is based on a fork of the goTrue server.</li>
<li>Realtime: This is an API that adds the ability to use real-time capabilities in your applications.</li>
<li>Storage: This is a storage service which is an s3 wrapper.</li>
<li>Edge Functions: These are serverless functions that run on the edge. Powered by the Deno runtime.</li>
<li>Vector: This is a vector database that makes it easier to work with embeddings in your AI applications.</li>
</ul>
<p>Supabase is SOC2, HIPAA and GDPR compliant, self-host-able and open source. Furthermore, their authentication service exposes many strategies, giving you full control over your data and can be used independently of their other offerings. This and their auto documenting API makes it a very good choice for your applications. </p>
<h3 id="heading-how-to-use-supabase-auth">How to use Supabase Auth</h3>
<p>The first step is to set up your <a target="_blank" href="https://app.supabase.com/">Supabase project</a>'s auth settings. You can enable the exact authentication methods you want to use via the settings. There are three ways you can start using Supabase auth in your project:</p>
<h4 id="heading-the-api">The API</h4>
<p>You can directly use the authentication service in your applications by calling the auth endpoint and passing the user information to it. You can also get, update and delete your users.   </p>
<p>The API is automatically available when you create a project via the Supabase console and can be called like so: </p>
<pre><code class="lang-javascript"><span class="hljs-comment">//This will return an object containing an access token, the newly created user data and other metadata</span>
<span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"https://&lt;your-project-ref&gt;/auth/v1/signup"</span>, {
  <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
  <span class="hljs-attr">headers</span>: {
    <span class="hljs-attr">authorization</span>: <span class="hljs-string">"Bearer YOUR_SUPABASE_KEY"</span>,
    <span class="hljs-string">"content-type"</span>: <span class="hljs-string">"application/json"</span>,
  },
  <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
    <span class="hljs-attr">email</span>: <span class="hljs-string">"user-email"</span>,
    <span class="hljs-attr">password</span>: <span class="hljs-string">"user-password"</span>,
  }),
});
</code></pre>
<h4 id="heading-sdks">SDKs</h4>
<p>Supabase offers a few SDKs (software development kits) in different programming languages meant to make interacting with your Supabase project straightforward. Languages officially supported include Dart and JavaScript, with Python and others having strong community support. </p>
<p>The procedure for getting started involves adding the SDK as a dependency, then connecting your application to your Supabase project. </p>
<p>In the case of the JavaScript SDK, this would look something like this:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//Install via npm:</span>
npm install @supabase/supabase-js

<span class="hljs-comment">// or add cdn links: </span>
&lt;script src=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2"</span>&gt;&lt;/script&gt;
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-comment">//Then initialize </span>
Supabaseimport { createClient } <span class="hljs-keyword">from</span> <span class="hljs-string">'@supabase/supabase-js'</span>

<span class="hljs-keyword">const</span> supabaseUrl = <span class="hljs-string">'https://&lt;your-project-ref&gt;.supabase.co'</span>
<span class="hljs-keyword">const</span> supabaseKey = process.env.SUPABASE_ANON_KEY
<span class="hljs-keyword">const</span> supabase = createClient(supabaseUrl, supabaseKey)
</code></pre>
<p>Then you can access the authentication methods under the auth namespace like so:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { data, error } = <span class="hljs-keyword">await</span> supabase.auth.signUp({
  <span class="hljs-attr">email</span>: <span class="hljs-string">'user email'</span>,
  <span class="hljs-attr">password</span>: <span class="hljs-string">'user password'</span>,
})
</code></pre>
<h4 id="heading-auth-ui-helpers">Auth UI Helpers</h4>
<p>Supabase provides helper libraries to make authentication using their service even easier. These libraries provide customizable login screens that support magic links, password based and social login strategies. </p>
<p>Currently, the libraries are available for JavaScript and Flutter. Supabase also provides a separate SSR (Server Side Rendering) package for applications that use server side frameworks and require a Supabase access token to be available to them.</p>
<p>To start using React Auth UI, as an example, first you need to install the dependencies as shown below:</p>
<pre><code class="lang-bash">npm install @supabase/supabase-js @supabase/auth-ui-react 
@supabase/auth-ui-shared
</code></pre>
<p>Then you can start using the library after initializing Supabase as in the SDK example above. Here is some sample code that shows how to use the auth UI library in a React application:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useNavigate } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> { Auth } <span class="hljs-keyword">from</span> <span class="hljs-string">"@supabase/auth-ui-react"</span>;
<span class="hljs-keyword">import</span> { ThemeSupa } <span class="hljs-keyword">from</span> <span class="hljs-string">"@supabase/auth-ui-shared"</span>;
<span class="hljs-keyword">import</span> { supa } <span class="hljs-keyword">from</span> <span class="hljs-string">"../constants"</span>;

<span class="hljs-keyword">const</span> AuthUi = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> navigate = useNavigate();

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> {
      <span class="hljs-attr">data</span>: { subscription },
    } = supa.auth.onAuthStateChange(<span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
      <span class="hljs-keyword">if</span> (event === <span class="hljs-string">"SIGNED_IN"</span>) {
        navigate(<span class="hljs-string">"/authenticated"</span>);
      }
    });

    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> subscription.unsubscribe();
  }, [navigate]);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Auth</span>
      <span class="hljs-attr">supabaseClient</span>=<span class="hljs-string">{supa}</span>
      <span class="hljs-attr">providers</span>=<span class="hljs-string">{[</span>"<span class="hljs-attr">google</span>", "<span class="hljs-attr">github</span>", "<span class="hljs-attr">apple</span>", "<span class="hljs-attr">discord</span>"]}
      // <span class="hljs-attr">controls</span> <span class="hljs-attr">whether</span> <span class="hljs-attr">to</span> <span class="hljs-attr">display</span> <span class="hljs-attr">only</span> <span class="hljs-attr">social</span> <span class="hljs-attr">providers</span>
      // <span class="hljs-attr">onlyThirdPartyProviders</span>
      <span class="hljs-attr">redirectTo</span>=<span class="hljs-string">"http://localhost:3000/authenticated"</span>
      // <span class="hljs-attr">comes</span> <span class="hljs-attr">with</span> <span class="hljs-attr">preconfigured</span> <span class="hljs-attr">themes</span>, <span class="hljs-attr">can</span> <span class="hljs-attr">add</span> <span class="hljs-attr">custom</span> <span class="hljs-attr">themes</span>
      <span class="hljs-attr">appearance</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">theme:</span> <span class="hljs-attr">ThemeSupa</span> }}
      // <span class="hljs-attr">controls</span> <span class="hljs-attr">how</span> <span class="hljs-attr">to</span> <span class="hljs-attr">display</span> <span class="hljs-attr">the</span> <span class="hljs-attr">social</span> <span class="hljs-attr">provider</span> <span class="hljs-attr">icons</span>
      <span class="hljs-attr">socialLayout</span>=<span class="hljs-string">"horizontal"</span>
    /&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> AuthUi;
</code></pre>
<p>This would display the following form on screen: </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/Screenshot-2024-01-26-at-18.43.39.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-summary">Summary</h2>
<p>Authentication is the process of the user identifying themselves and the server verifying this identity while authorization is the system determining what access the user should have to the resources and limiting the user accordingly.</p>
<p>After the server authenticates the user, it will pass the user information in the form of either a token or session ID within a cookie. </p>
<p>The information will be passed back and forth between the client and server whenever the user needs certain access until they expire or the user terminates the cycle by logging out or deleting their account.</p>
<p>This process of user verification occurs by employing certain factors of authentication. For example, one system may only require a password while another requires a password and a code sent to the users phone number.</p>
<p>Your authentication system can allow multiple strategies of authentication using any of the three auth factors.</p>
<p>Supabase is an excellent option if you opt not to handle your own auth.</p>
<p>Supabase auth can be accessed via the API, the SDKs and the Auth libraries. Supabase maintains an SSR package for server side frameworks.</p>
<h2 id="heading-resources">Resources</h2>
<p>The following resources are helpful further reading. They offer more explanations on authentication and authorization, as well as Supabase specific documentation.</p>
<ul>
<li><a target="_blank" href="https://www.upguard.com/blog/oauth#:~:text=OAuth%201.0%20has%20a%20consumer,resource%20server%2C%20and%20resource%20owner.">An indepth explanation of OAuth</a></li>
<li><a target="_blank" href="https://supabase.com/security">Supabase security</a></li>
<li><a target="_blank" href="https://supabase.com/docs/guides/auth">Supabase docs on authentication</a></li>
<li><a target="_blank" href="https://supabase.com/docs/guides/auth/auth-helpers/auth-ui">Auth UI docs page</a></li>
<li><a target="_blank" href="https://supabase.com/docs/guides/auth/auth-helpers">Supabase on auth helpers and SSR</a></li>
<li><a target="_blank" href="https://supabase.com/docs/guides/auth/sso/auth-sso-saml">On SSO, SAML and enterprise auth</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Secure Your MERN Stack App with JWT-Based User Authentication and Authorization ]]>
                </title>
                <description>
                    <![CDATA[ By FADAHUNSI SEYI SAMUEL MongoDB, Express, React, and Node.js are the components of the MERN stack, one of the most widely used web development stacks out there today. The MERN stack enables programmers to create dependable web applications with stro... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-secure-your-mern-stack-application/</link>
                <guid isPermaLink="false">66d45edb7df3a1f32ee7f859</guid>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ authorization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express JS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 15 May 2023 17:15:14 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/05/trlyJUK.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By FADAHUNSI SEYI SAMUEL</p>
<p><a target="_blank" href="https://www.mongodb.com/docs/">MongoDB</a>, <a target="_blank" href="https://expressjs.com/en/starter/installing.html">Express</a>, <a target="_blank" href="https://react.dev/learn">React</a>, and <a target="_blank" href="https://nodejs.org/en/docs">Node.js</a> are the components of the MERN stack, one of the most widely used web development stacks out there today.</p>
<p>The MERN stack enables programmers to create dependable web applications with strong capabilities. Yet, security should be a key concern with any web application.</p>
<p>User authentication and permissions are some of the most important security features of any web service. In order to protect sensitive information and stop unauthorized access to important functions, these make sure that only authorized users can access certain areas of the application.</p>
<p>By the end of this article, you will have a firm grasp on how to integrate <a target="_blank" href="https://jwt.io/introduction">JWT</a>  (Json Web Token)-based user authentication and authorization into your MERN stack web application.</p>
<h3 id="heading-heres-what-well-cover">Here's what we'll cover:</h3>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-user-authentication-amp-authorization">What is User Authentication &amp; Authorization?</a></li>
<li><a class="post-section-overview" href="#heading-what-is-the-mern-stack">What is the MERN Stack?</a></li>
<li><a class="post-section-overview" href="#heading-why-use-the-mern-stack">Why Use the MERN Stack?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-the-project-environment">How to Set Up the Project Environment</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-a-new-react-application">How to Create a New React Application</a></li>
<li><a class="post-section-overview" href="#heading-nodejs-and-expressjs-installation-and-configuration">Node.js and Express.js Installation and Configuration</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-mongodb">How to Set Up MongoDB</a></li>
<li><a class="post-section-overview" href="#heading-how-to-implement-the-backend">How to Implement the Backend</a></li>
<li><a class="post-section-overview" href="#heading-how-to-handle-the-signup-route">How to Handle the SIGNUP Route</a></li>
<li><a class="post-section-overview" href="#heading-how-to-handle-the-login-route">How to Handle the LOGIN Route</a></li>
<li><a class="post-section-overview" href="#heading-how-to-handle-the-home-route">How to Handle the HOME Route</a></li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/p/43c39ded-b2ce-4029-8fbe-66015525449f/howtoimplementthefrontend">How to Implement the Frontend</a></li>
<li><a class="post-section-overview" href="#heading-how-to-handle-the-signup-logic">How to Handle the Signup Logic</a></li>
<li><a class="post-section-overview" href="#heading-how-to-handle-the-login-logic">How to Handle the Login Logic</a></li>
<li><a class="post-section-overview" href="#heading-how-to-handle-the-home-page-logic">How to Handle the Home Page Logic</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ul>
<h2 id="heading-what-is-user-authentication-amp-authorization">What is User Authentication &amp; Authorization?</h2>
<p>In application security, authentication and authorization are two crucial ideas that work together to guarantee access to the resources of an application. </p>
<p>Many people frequently confuse these words – but after reading this guide, will we? NOT AGAIN!</p>
<h3 id="heading-authentication">Authentication</h3>
<p>Verifying a user's or an entity's identity is the process called  <strong>Authentication</strong>. It entails validating the user's credentials, such as a username and password, to ensure that the user is who they claim to be.</p>
<h3 id="heading-authorization">Authorization</h3>
<p>The process of authorizing or refusing access to particular resources or functions within an application is known as <strong>Authorization</strong>. Once a user has been verified as authentic, the program checks their level of authorization to decide which areas of the application they can access.</p>
<p><strong>Authentication</strong> is comparable to when a college applicant is admitted to a program based on the results of a written exam. The student is permitted on school grounds, but is not permitted in a department or class that is not their own (that was not given to them during admission). This action is known as <strong>Authorization</strong>.</p>
<h2 id="heading-what-is-the-mern-stack">What is the MERN Stack?</h2>
<p>Let's talk about the various elements of the MERN stack before we start creating the authentication mechanism.</p>
<ol>
<li><strong>MongoDB</strong> is a NoSQL database that uses dynamic schemas and documents that resemble JSON to store data. MongoDB is a popular option for creating scalable web applications because it is effective at managing big amounts of data.</li>
<li><strong>Express.js</strong> is a Node.js web application framework that offers a selection of functionality for creating online applications. Express.js is a well-liked option for developing online applications since it is compact, quick, and simple to use.</li>
<li><strong>React.js</strong> is a JavaScript library used to create user interfaces. By disassembling complicated user interfaces into smaller, reusable components, React.js offers a declarative method for doing so.</li>
<li><strong>Node.js</strong> is based on the V8 JavaScript engine in Chrome, and is a JavaScript runtime. The ability to run JavaScript on the server-side makes Node.js the perfect platform for creating web applications.</li>
</ol>
<h2 id="heading-why-use-the-mern-stack">Why Use the MERN Stack?</h2>
<p>The MERN stack is a great option for developing web applications since it includes all of the technologies needed to create a cutting-edge, scalable online application.</p>
<p>Following a discussion of the various elements of the MERN stack, we will use code snippets to develop a whole user authentication system from scratch.</p>
<h2 id="heading-how-to-set-up-the-project-environment">How to Set Up the Project Environment</h2>
<p>To get started with building the authentication system, we first need to set up the project. We will create a new React application using <code>create-react-app</code> and install the required dependencies. We will also set up <code>MongoDB</code> and configure our <code>Node.js</code> server.</p>
<p>NB: In this article, we will be making use of <a target="_blank" href="https://code.visualstudio.com/download">Visual studio code</a> editor, which I highly recommend.</p>
<p>Before we dive into this, you're going to create a folder which will contain other sub folders as you move on in this article.</p>
<p>After creating your folder, it should look like the image below:</p>
<p><img src="https://i.imgur.com/JrxZbI3.png" alt="Folder structure" width="600" height="400" loading="lazy"></p>
<p>The folder you just created will contain two sub folders called the <code>client</code> and <code>server</code>. Run the commands below in your terminal to create the sub folders:</p>
<pre><code>mkdir client
</code></pre><p>This will create the <code>client</code> sub folder.</p>
<pre><code>mkdir server
</code></pre><p>This will create the <code>server</code> sub folder. Your application folder should look like this:</p>
<p><img src="https://i.imgur.com/jwPj09J.png" alt="Application folder" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-create-a-new-react-application">How to Create a New React Application</h3>
<p>You can create a new React application using <code>create-react-app</code>. Open your terminal and run the below command to create a new React application.</p>
<p>But first, you will need to go into the <code>client</code> folder using <code>cd client</code>, then run the following command:</p>
<pre><code class="lang-shell">npx create-react-app
</code></pre>
<p>After the command above has successfully created the app, type <code>npm start</code> in your terminal. Make sure you're in your <code>client</code> directory. Your output should look like the image below:</p>
<p><img src="https://i.imgur.com/Y8N9gbL.png" alt="Y8N9gbL" width="600" height="400" loading="lazy"></p>
<p>Before we move to the server directory, you will need to remove some boilerplate in your React application. Your <code>client</code> should look like the image below;</p>
<p><img src="https://i.imgur.com/27WytE6.png" alt="27WytE6" width="600" height="400" loading="lazy"></p>
<p>Once you're done with the above, restart your React application by running <code>npm start</code> in your terminal. Your application should be looking like this:</p>
<p><img src="https://i.imgur.com/ws2F4wH.png" alt="ws2F4wH" width="600" height="400" loading="lazy"></p>
<p>Now, you've successfully setup your client side of the application 😊 yeah!</p>
<h3 id="heading-nodejs-and-expressjs-installation-and-configuration">Node.js and Express.js Installation and Configuration</h3>
<p>To setup your backend application, run <code>mkdir server</code> in your terminal to get into the <code>server</code> sub folder. After getting into the <code>server</code> sub folder, run the following command to initialize the backend application:</p>
<pre><code class="lang-shell">npm init --yes
</code></pre>
<p>The <code>npm init --yes</code> command in Node.js creates a new <code>package.json</code> file for a project with default settings, without asking the user any questions.</p>
<p>The <code>--yes</code> or <code>-y</code> flag tells npm to use default values for all prompts that would normally appear during the initialization process.</p>
<p>The server folder should now contain a <code>package.json</code> file just like so:</p>
<pre><code class="lang-javascript">{
  <span class="hljs-string">"name"</span>: <span class="hljs-string">"server"</span>,
  <span class="hljs-string">"version"</span>: <span class="hljs-string">"1.0.0"</span>,
  <span class="hljs-string">"description"</span>: <span class="hljs-string">""</span>,
  <span class="hljs-string">"main"</span>: <span class="hljs-string">"index.js"</span>,
  <span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"test"</span>: <span class="hljs-string">"echo \"Error: no test specified\" &amp;&amp; exit 1"</span>
  },
  <span class="hljs-string">"keywords"</span>: [],
  <span class="hljs-string">"author"</span>: <span class="hljs-string">""</span>,
  <span class="hljs-string">"license"</span>: <span class="hljs-string">"ISC"</span>
}
</code></pre>
<p>To install Express.js and other dependencies, run the following commands in your terminal:</p>
<pre><code class="lang-shell"> npm install express cors bcrypt cookie-parser nodemon jsonwebtoken mongoose dotenv
</code></pre>
<p>The above commands install the following dependencies:</p>
<ul>
<li><code>Express.js</code>, which is our Node.js web application framework.</li>
<li><code>bcrypt</code>, which helps us hash the user's password.</li>
<li><code>cookie-parser</code> is the the cookie-parser middleware that handles cookie-based sessions. It extracts information from cookies that may be required for authentication or other purposes.</li>
<li><code>nodemon</code> is a tool used to automatically restart a Node.js application whenever changes are made to the code. </li>
<li><code>CORS</code> is a middleware used to enable Cross-Origin Resource Sharing (CORS) for an Express.js application.</li>
<li><code>jsonwebtoken</code> helps us create and verify JSON Web Tokens. </li>
<li><code>dotenv</code> allows you to store configuration data in a <code>.env</code> file, which is typically not committed to version control, to separate sensitive information from your codebase. This file contains key-value pairs that represent the environment variables.</li>
</ul>
<p>After installing the required dependencies, create a new file called <code>index.js</code> in the root directory of your <code>server</code> sub folder of your application. The <code>index.js</code> file will contain our Node.js server. </p>
<p>In the <code>index.js</code> file of your <code>server</code>, add the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);

<span class="hljs-keyword">const</span> app = express();
<span class="hljs-keyword">const</span> PORT = <span class="hljs-number">4000</span>;

app.listen(PORT, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server is listening on port <span class="hljs-subst">${PORT}</span>`</span>);
});
</code></pre>
<p>Before you start the server, update your <code>package.json</code> file in the server by adding the code below:</p>
<pre><code class="lang-javascript">  <span class="hljs-string">"scripts"</span>:{
  <span class="hljs-attr">start</span>: <span class="hljs-string">"nodemon index.js"</span>,
  <span class="hljs-attr">test</span>: <span class="hljs-string">'echo "Error: no test specified" &amp;&amp; exit 1'</span>,
};
</code></pre>
<p>This will make sure your application restarts on any update. Now, you can start your <code>server</code> by running <code>npm start</code> in your terminal.</p>
<p>If all these are successfully executed, your terminal should look like this:</p>
<p><img src="https://i.imgur.com/EsjRkqi.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-set-up-mongodb">How to Set Up MongoDB</h3>
<p>You're almost done with setting up your application. If you do not have <code>mongodb</code> installed your computer, follow these <a target="_blank" href="https://www.mongodb.com/docs/manual/installation/">steps</a>.</p>
<p>Now, I assume you have successfully installed <code>mongodb</code> on your computer. To link your database to your backend, follow the procedures below.</p>
<p>STEP 1: Go into your MongoDB cloud clusters, which should look like the image below:</p>
<p><img src="https://i.imgur.com/MZbppS2.png" alt="MZbppS2" width="600" height="400" loading="lazy"></p>
<p>STEP 2: Click on the Database Access, which is on the left of the sidebar. Click on <code>ADD NEW DATABASE USER</code> which will pop up a modal, like the image below:</p>
<p><img src="https://i.imgur.com/Hyiky7V.png" alt="Hyiky7V" width="600" height="400" loading="lazy"></p>
<p>STEP 3: Fill out the <code>Password Authentication</code> with your desired username and password for the database of this particular project.</p>
<p>STEP 4: Before saving this, click the <code>Built-in Role</code> dropdown, and select <code>Read and write to any database</code>. Now, go ahead to click <code>Add user</code>.</p>
<p>STEP 5: Click on <code>Database</code>, and on the left side of the sidebar, click the <code>connect</code> button, which is beside <code>View Monitoring</code>. A modal popup will be displayed, then click <code>connect your application</code> and copy the code snippet you find there.</p>
<p><img src="https://i.imgur.com/Hqmbxro.png" alt="Hqmbxro" width="600" height="400" loading="lazy"></p>
<p>You will replace <code>&lt;username&gt;</code> and <code>&lt;password&gt;</code> with the username and password you created in <code>STEP 3</code> in your <code>index.js</code> file in the server folder.</p>
<p>Before going into your <code>index.js</code> file, you will create a <code>.env</code> file in your <code>server</code> directory, which will contain your <code>MONGODB_URL</code>, <code>PORT</code>, <code>database_name</code>, and <code>database_password</code> like the code below:</p>
<pre><code class="lang-javascript">MONGO_URL =
  <span class="hljs-string">"mongodb+srv://database_name:database_password@cluster0.fbx6x.mongodb.net/?retryWrites=true&amp;w=majority"</span>;
PORT = <span class="hljs-number">4000</span>;
</code></pre>
<p>Once you're done with this, go into your <code>index.js</code> in your <code>server</code> directory, and update it with the code below:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);
<span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">"mongoose"</span>);
<span class="hljs-keyword">const</span> cors = <span class="hljs-built_in">require</span>(<span class="hljs-string">"cors"</span>);
<span class="hljs-keyword">const</span> app = express();
<span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv"</span>).config();
<span class="hljs-keyword">const</span> { MONGO_URL, PORT } = process.env;

mongoose
  .connect(MONGO_URL, {
    <span class="hljs-attr">useNewUrlParser</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">useUnifiedTopology</span>: <span class="hljs-literal">true</span>,
  })
  .then(<span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"MongoDB is  connected successfully"</span>))
  .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> <span class="hljs-built_in">console</span>.error(err));

app.listen(PORT, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server is listening on port <span class="hljs-subst">${PORT}</span>`</span>);
});

app.use(
  cors({
    <span class="hljs-attr">origin</span>: [<span class="hljs-string">"http://localhost:4000"</span>],
    <span class="hljs-attr">methods</span>: [<span class="hljs-string">"GET"</span>, <span class="hljs-string">"POST"</span>, <span class="hljs-string">"PUT"</span>, <span class="hljs-string">"DELETE"</span>],
    <span class="hljs-attr">credentials</span>: <span class="hljs-literal">true</span>,
  })
);

app.use(express.json());
</code></pre>
<p>In the code above, we are configuring our application to be able to have access to the <code>.env</code> file. You can get the information in your <code>.env</code> file by doing <code>process.env</code>.</p>
<p>So you're destructing the values from the <code>.env</code> file by doing <code>process.env</code> so you don't repeat yourself (DRY) which is a good engineering practice.</p>
<ul>
<li>CORS (Cross origin resource sharing): You can allow requests from other domains to access the resources on your server by using the <code>cors()</code> express middleware function. The CORS headers that your server should include in the response can be specified using the function's optional configuration object parameter, which is taken as a parameter by the function which is the <code>origin</code>, <code>methods</code> and <code>credentials</code>.</li>
<li>express.json(): The <code>express.json()</code> will add a <code>body</code> property to the <code>request</code> or <code>req</code> object. This includes the request body's parsed JSON data. <code>req.body</code> in your route handler function will allow you to access this data.</li>
<li>useNewUrlParser: This property specifies that Mongoose should use the new URL parser to parse MongoDB connection strings. This is set to true by default.</li>
<li>useUnifiedTopology: This property specifies that Mongoose should use the new Server Discovery and Monitoring engine. This is set to false by default.</li>
</ul>
<p>After following the steps above, you will restart your application by doing <code>npm start</code> in your <code>server</code> directory. Your terminal should look like the image below;</p>
<p><img src="https://i.imgur.com/Ly8zIk5.png" alt="Ly8zIk5" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-implement-the-backend">How to Implement the Backend</h2>
<p>Create the following folders in the <code>server</code> directory of your application after first ensuring that you are in that directory. <code>Controllers</code>, <code>Middlewares</code>, <code>Routes</code>, <code>Models</code>, and <code>util</code> are the names of these folders.</p>
<h3 id="heading-how-to-handle-the-signup-route">How to Handle the SIGNUP Route</h3>
<p>Create a file called <code>UserModel.js</code> in the <code>Models</code> directory and put the following code into it to get started:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">"mongoose"</span>);
<span class="hljs-keyword">const</span> bcrypt = <span class="hljs-built_in">require</span>(<span class="hljs-string">"bcryptjs"</span>);

<span class="hljs-keyword">const</span> userSchema = <span class="hljs-keyword">new</span> mongoose.Schema({
  <span class="hljs-attr">email</span>: {
    <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
    <span class="hljs-attr">required</span>: [<span class="hljs-literal">true</span>, <span class="hljs-string">"Your email address is required"</span>],
    <span class="hljs-attr">unique</span>: <span class="hljs-literal">true</span>,
  },
  <span class="hljs-attr">username</span>: {
    <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
    <span class="hljs-attr">required</span>: [<span class="hljs-literal">true</span>, <span class="hljs-string">"Your username is required"</span>],
  },
  <span class="hljs-attr">password</span>: {
    <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
    <span class="hljs-attr">required</span>: [<span class="hljs-literal">true</span>, <span class="hljs-string">"Your password is required"</span>],
  },
  <span class="hljs-attr">createdAt</span>: {
    <span class="hljs-attr">type</span>: <span class="hljs-built_in">Date</span>,
    <span class="hljs-attr">default</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(),
  },
});

userSchema.pre(<span class="hljs-string">"save"</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">this</span>.password = <span class="hljs-keyword">await</span> bcrypt.hash(<span class="hljs-built_in">this</span>.password, <span class="hljs-number">12</span>);
});

<span class="hljs-built_in">module</span>.exports = mongoose.model(<span class="hljs-string">"User"</span>, userSchema);
</code></pre>
<p>The user schema and user password will be created in the above code using <code>mongoose</code> and <code>bcryptjs</code>, respectively, for security purposes.</p>
<p>The <code>password</code> is hashed for security reasons prior to saving the user.</p>
<p>Next, you will setup a function to handle the generation of a atoken, which will be called <code>SecretToken.js</code> in the <code>util</code> folder. Copy and paste the code below into the newly created file (<code>SecretToken.js</code>):</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv"</span>).config();
<span class="hljs-keyword">const</span> jwt = <span class="hljs-built_in">require</span>(<span class="hljs-string">"jsonwebtoken"</span>);

<span class="hljs-built_in">module</span>.exports.createSecretToken = <span class="hljs-function">(<span class="hljs-params">id</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> jwt.sign({ id }, process.env.TOKEN_KEY, {
    <span class="hljs-attr">expiresIn</span>: <span class="hljs-number">3</span> * <span class="hljs-number">24</span> * <span class="hljs-number">60</span> * <span class="hljs-number">60</span>,
  });
};
</code></pre>
<p>Once that's done, create a file called <code>AuthController.js</code> in the <code>Controllers</code> directory and paste in the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> User = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../Models/UserModel"</span>);
<span class="hljs-keyword">const</span> { createSecretToken } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../util/SecretToken"</span>);
<span class="hljs-keyword">const</span> bcrypt = <span class="hljs-built_in">require</span>(<span class="hljs-string">"bcryptjs"</span>);

<span class="hljs-built_in">module</span>.exports.Signup = <span class="hljs-keyword">async</span> (req, res, next) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> { email, password, username, createdAt } = req.body;
    <span class="hljs-keyword">const</span> existingUser = <span class="hljs-keyword">await</span> User.findOne({ email });
    <span class="hljs-keyword">if</span> (existingUser) {
      <span class="hljs-keyword">return</span> res.json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"User already exists"</span> });
    }
    <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> User.create({ email, password, username, createdAt });
    <span class="hljs-keyword">const</span> token = createSecretToken(user._id);
    res.cookie(<span class="hljs-string">"token"</span>, token, {
      <span class="hljs-attr">withCredentials</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">httpOnly</span>: <span class="hljs-literal">false</span>,
    });
    res
      .status(<span class="hljs-number">201</span>)
      .json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"User signed in successfully"</span>, <span class="hljs-attr">success</span>: <span class="hljs-literal">true</span>, user });
    next();
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(error);
  }
};
</code></pre>
<p>The user's inputs are obtained from the <code>req.body</code> in the code above, and you then check the <code>email</code> to make sure no past registrations have been made. We'll use the values obtained from <code>req.body</code> to create the new <code>user</code> after that has occurred.</p>
<p>You don't need to worry about how the unique <code>_id</code> was obtained because MongoDB always assigns a new user with a unique <code>_id</code></p>
<p>The newly formed <code>user</code>'s <code>_id</code> is then supplied as an parameter to the <code>createSecretToken()</code> function, which handles token generation.</p>
<p>The <code>cookie</code> will be sent to the client with key of <code>"token"</code>, and value of <code>token</code>.</p>
<p>Next, create a file called <code>AuthRoute.js</code> in the <code>Routes</code> directory. Paste the code below into the newly created file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { Signup } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../Controllers/AuthController"</span>);
<span class="hljs-keyword">const</span> router = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>).Router();

router.post(<span class="hljs-string">"/signup"</span>, Signup);

<span class="hljs-built_in">module</span>.exports = router;
</code></pre>
<p>In the code above, the <code>/signup</code> route has a <code>post</code> method attached to it, when it's been called, the <code>Signup</code> controller will be executed.</p>
<p>Next, update your <code>index.js</code> file so it can be aware of the routes. Your <code>index.js</code> file should look like the code below:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);
<span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">"mongoose"</span>);
<span class="hljs-keyword">const</span> cors = <span class="hljs-built_in">require</span>(<span class="hljs-string">"cors"</span>);
<span class="hljs-keyword">const</span> app = express();
<span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv"</span>).config();
<span class="hljs-keyword">const</span> cookieParser = <span class="hljs-built_in">require</span>(<span class="hljs-string">"cookie-parser"</span>);
<span class="hljs-keyword">const</span> authRoute = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./Routes/AuthRoute"</span>);
<span class="hljs-keyword">const</span> { MONGO_URL, PORT } = process.env;

mongoose
  .connect(MONGO_URL, {
    <span class="hljs-attr">useNewUrlParser</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">useUnifiedTopology</span>: <span class="hljs-literal">true</span>,
  })
  .then(<span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"MongoDB is  connected successfully"</span>))
  .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> <span class="hljs-built_in">console</span>.error(err));

app.listen(PORT, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server is listening on port <span class="hljs-subst">${PORT}</span>`</span>);
});

app.use(
  cors({
    <span class="hljs-attr">origin</span>: [<span class="hljs-string">"http://localhost:3000"</span>],
    <span class="hljs-attr">methods</span>: [<span class="hljs-string">"GET"</span>, <span class="hljs-string">"POST"</span>, <span class="hljs-string">"PUT"</span>, <span class="hljs-string">"DELETE"</span>],
    <span class="hljs-attr">credentials</span>: <span class="hljs-literal">true</span>,
  })
);
app.use(cookieParser());

app.use(express.json());

app.use(<span class="hljs-string">"/"</span>, authRoute);
</code></pre>
<p>The <code>cookie-parser</code> manages cookie-based sessions or extracts data from cookies. It's added to the code above along with the <code>authRoute</code> that the application will utilize.</p>
<p>Now, let's go ahead to test the <code>/signup</code> route with a tool called <a target="_blank" href="https://www.postman.com/downloads/">Postman</a>. Make sure you're in the <code>server</code> directory in the terminal, then run <code>npm start</code> to start your application.</p>
<p><img src="https://i.imgur.com/zzN1QyQ.png" alt="zzN1QyQ" width="600" height="400" loading="lazy"></p>
<p>The image above shows the response gotten when a request is sent.</p>
<p><img src="https://i.imgur.com/8jrGe0T.png" alt="8jrGe0T" width="600" height="400" loading="lazy"></p>
<p>The image above shows the generated cookie from the response.</p>
<p><img src="https://i.imgur.com/KJ8haPB.png" alt="KJ8haPB" width="600" height="400" loading="lazy"></p>
<p>The image above illustrates what happens when you try to use a registered email.</p>
<p>By now, the user will be created in the database like the image below:</p>
<p><img src="https://i.imgur.com/XQsjWRt.png" alt="XQsjWRt" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-handle-the-login-route">How to Handle the LOGIN Route</h3>
<p>Open the <code>AuthController.js</code> file in the <code>Controllers</code> directory, and update it with the code below:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">module</span>.exports.Login = <span class="hljs-keyword">async</span> (req, res, next) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> { email, password } = req.body;
    <span class="hljs-keyword">if</span>(!email || !password ){
      <span class="hljs-keyword">return</span> res.json({<span class="hljs-attr">message</span>:<span class="hljs-string">'All fields are required'</span>})
    }
    <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> User.findOne({ email });
    <span class="hljs-keyword">if</span>(!user){
      <span class="hljs-keyword">return</span> res.json({<span class="hljs-attr">message</span>:<span class="hljs-string">'Incorrect password or email'</span> }) 
    }
    <span class="hljs-keyword">const</span> auth = <span class="hljs-keyword">await</span> bcrypt.compare(password,user.password)
    <span class="hljs-keyword">if</span> (!auth) {
      <span class="hljs-keyword">return</span> res.json({<span class="hljs-attr">message</span>:<span class="hljs-string">'Incorrect password or email'</span> }) 
    }
     <span class="hljs-keyword">const</span> token = createSecretToken(user._id);
     res.cookie(<span class="hljs-string">"token"</span>, token, {
       <span class="hljs-attr">withCredentials</span>: <span class="hljs-literal">true</span>,
       <span class="hljs-attr">httpOnly</span>: <span class="hljs-literal">false</span>,
     });
     res.status(<span class="hljs-number">201</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"User logged in successfully"</span>, <span class="hljs-attr">success</span>: <span class="hljs-literal">true</span> });
     next()
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(error);
  }
}
</code></pre>
<p>You are determining in the code above whether the <code>email</code> and <code>password</code> match any previously stored <code>user</code> in the database.</p>
<p>Then add the following code to the file <code>AuthRoute.js</code> in the <code>Routes</code> directory:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { Signup, Login } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../Controllers/AuthController'</span>)
<span class="hljs-keyword">const</span> router = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>).Router()

router.post(<span class="hljs-string">'/signup'</span>, Signup)
router.post(<span class="hljs-string">'/login'</span>, Login)

<span class="hljs-built_in">module</span>.exports = router
</code></pre>
<p>Now, let's go ahead to test the application:</p>
<p><img src="https://i.imgur.com/gwRjAGk.png" alt="gwRjAGk" width="600" height="400" loading="lazy"></p>
<p>If you try to use an unregistered <code>email</code> or <code>password</code>, you'll get the message below:</p>
<p><img src="https://i.imgur.com/fLj20iU.png" alt="fLj20iU" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-handle-the-home-route">How to Handle the HOME Route</h3>
<p>Now, you will create a <code>AuthMiddleware.js</code> file, in the <code>Middlewares</code> directory, and paste in the code below:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> User = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../Models/UserModel"</span>);
<span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv"</span>).config();
<span class="hljs-keyword">const</span> jwt = <span class="hljs-built_in">require</span>(<span class="hljs-string">"jsonwebtoken"</span>);

<span class="hljs-built_in">module</span>.exports.userVerification = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> token = req.cookies.token
  <span class="hljs-keyword">if</span> (!token) {
    <span class="hljs-keyword">return</span> res.json({ <span class="hljs-attr">status</span>: <span class="hljs-literal">false</span> })
  }
  jwt.verify(token, process.env.TOKEN_KEY, <span class="hljs-keyword">async</span> (err, data) =&gt; {
    <span class="hljs-keyword">if</span> (err) {
     <span class="hljs-keyword">return</span> res.json({ <span class="hljs-attr">status</span>: <span class="hljs-literal">false</span> })
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> User.findById(data.id)
      <span class="hljs-keyword">if</span> (user) <span class="hljs-keyword">return</span> res.json({ <span class="hljs-attr">status</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">user</span>: user.username })
      <span class="hljs-keyword">else</span> <span class="hljs-keyword">return</span> res.json({ <span class="hljs-attr">status</span>: <span class="hljs-literal">false</span> })
    }
  })
}
</code></pre>
<p>The code above checks if the user has access to the route by checking if the <code>token</code>s match.</p>
<p>Next, update the <code>AuthRoute.js</code> file in the <code>Routes</code> directory with the code below:</p>
<pre><code class="lang-javascript">router.post(<span class="hljs-string">'/'</span>,userVerification)
</code></pre>
<p>Now, you can go ahead to test your route. It should look like the image below:</p>
<p><img src="https://i.imgur.com/xk1J1Zs.png" alt="xk1J1Zs" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-implement-the-frontend">How to Implement the Frontend</h2>
<p>To get started, go into the <code>client</code> directory and install the following in your terminal:</p>
<pre><code class="lang-shell">npm install react-cookie react-router-dom react-toastify axios
</code></pre>
<p>Now, update the <code>index.js</code> file in the <code>client</code> directory with the code snippet below:</p>
<p><img src="https://i.imgur.com/LcoXMWB.png" alt="LcoXMWB" width="600" height="400" loading="lazy"></p>
<p>In the code above, wrapping your <code>App</code> component with <code>BrowserRouter</code> is necessary to enable client-side routing and take advantage of its benefits in your application.</p>
<p>NB: Remove the <code>React.StrictMode</code> later when you are testing the application and your data is being fetched twice.</p>
<p>Also, import <code>react-toastify</code> so it can be available in your application.</p>
<p>Now, go ahead to create the <code>pages</code> directory in your <code>client</code> directory, which will contain the <code>Home.jsx</code> file, <code>Login.jsx</code> file, <code>Signup.jsx</code> and <code>index.js</code> to export the components. Your folder should look like the image below:</p>
<p><img src="https://i.imgur.com/G4rQ48P.png" alt="G4rQ48P" width="600" height="400" loading="lazy"></p>
<p>Now, fill the <code>Login.jsx</code>, <code>Signup.jsx</code>, and <code>Home.jsx</code>, respectively, with the code below. These snippets below, are functional components which will be modified later in this guide. </p>
<p>NB: This can be automatically generated by typing the shortcut <code>rafce</code> + <code>enter</code> in the file you want to add the snippet in your visual studio code editor. Make sure this <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=dsznajder.es7-react-js-snippets">extension</a> is installed in your visual studio code for this to work.</p>
<p><code>Login.jsx</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> Login = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Login Page<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Login
</code></pre>
<p><code>Signup.jsx</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> Signup = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Signup Page<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Signup
</code></pre>
<p><code>Home.jsx</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> Home = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Home PAGE<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home
</code></pre>
<p>After that's done, you will go into the <code>index.js</code> file in the <code>pages</code> directory to export the newly created components. It should look like the image below:</p>
<p><img src="https://i.imgur.com/XKroJyH.png" alt="XKroJyH" width="600" height="400" loading="lazy"></p>
<p>The method shown above makes importing components easier by requiring only one import line.</p>
<p>Now, update the <code>App.js</code> file in the <code>src</code> directory with the code below.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Route, Routes } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> { Login, Signup } <span class="hljs-keyword">from</span> <span class="hljs-string">"./pages"</span>;
<span class="hljs-keyword">import</span> Home <span class="hljs-keyword">from</span> <span class="hljs-string">"./pages/Home"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Routes</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Home</span> /&gt;</span>} /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/login"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Login</span> /&gt;</span>} /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/signup"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Signup</span> /&gt;</span>} /&gt;
      <span class="hljs-tag">&lt;/<span class="hljs-name">Routes</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>The routes will be made available in your application using the above code. The example below will help to clarify:</p>
<p><img src="https://i.imgur.com/w78YqgX.gif" alt="w78YqgX" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-handle-the-signup-logic">How to Handle the Signup Logic</h3>
<p>In the <code>Signup.jsx</code> file in the <code>pages</code> directory, paste the following code snippet:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { Link, useNavigate } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
<span class="hljs-keyword">import</span> { ToastContainer, toast } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-toastify"</span>;

<span class="hljs-keyword">const</span> Signup = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> navigate = useNavigate();
  <span class="hljs-keyword">const</span> [inputValue, setInputValue] = useState({
    <span class="hljs-attr">email</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">password</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">username</span>: <span class="hljs-string">""</span>,
  });
  <span class="hljs-keyword">const</span> { email, password, username } = inputValue;
  <span class="hljs-keyword">const</span> handleOnChange = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> { name, value } = e.target;
    setInputValue({
      ...inputValue,
      [name]: value,
    });
  };

  <span class="hljs-keyword">const</span> handleError = <span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span>
    toast.error(err, {
      <span class="hljs-attr">position</span>: <span class="hljs-string">"bottom-left"</span>,
    });
  <span class="hljs-keyword">const</span> handleSuccess = <span class="hljs-function">(<span class="hljs-params">msg</span>) =&gt;</span>
    toast.success(msg, {
      <span class="hljs-attr">position</span>: <span class="hljs-string">"bottom-right"</span>,
    });

  <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-keyword">async</span> (e) =&gt; {
    e.preventDefault();
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> axios.post(
        <span class="hljs-string">"http://localhost:4000/signup"</span>,
        {
          ...inputValue,
        },
        { <span class="hljs-attr">withCredentials</span>: <span class="hljs-literal">true</span> }
      );
      <span class="hljs-keyword">const</span> { success, message } = data;
      <span class="hljs-keyword">if</span> (success) {
        handleSuccess(message);
        <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
          navigate(<span class="hljs-string">"/"</span>);
        }, <span class="hljs-number">1000</span>);
      } <span class="hljs-keyword">else</span> {
        handleError(message);
      }
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.log(error);
    }
    setInputValue({
      ...inputValue,
      <span class="hljs-attr">email</span>: <span class="hljs-string">""</span>,
      <span class="hljs-attr">password</span>: <span class="hljs-string">""</span>,
      <span class="hljs-attr">username</span>: <span class="hljs-string">""</span>,
    });
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form_container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Signup Account<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"email"</span>&gt;</span>Email<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"email"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{email}</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter your email"</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleOnChange}</span>
          /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"email"</span>&gt;</span>Username<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"username"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{username}</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter your username"</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleOnChange}</span>
          /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"password"</span>&gt;</span>Password<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"password"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{password}</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter your password"</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleOnChange}</span>
          /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>
          Already have an account? <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">{</span>"/<span class="hljs-attr">login</span>"}&gt;</span>Login<span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ToastContainer</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Signup;
</code></pre>
<h3 id="heading-how-to-handle-the-login-logic">How to Handle the Login Logic</h3>
<p>Add the following code snippet to the <code>Login.jsx</code> file in the <code>pages</code> directory:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { Link, useNavigate } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
<span class="hljs-keyword">import</span> { ToastContainer, toast } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-toastify"</span>;

<span class="hljs-keyword">const</span> Login = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> navigate = useNavigate();
  <span class="hljs-keyword">const</span> [inputValue, setInputValue] = useState({
    <span class="hljs-attr">email</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">password</span>: <span class="hljs-string">""</span>,
  });
  <span class="hljs-keyword">const</span> { email, password } = inputValue;
  <span class="hljs-keyword">const</span> handleOnChange = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> { name, value } = e.target;
    setInputValue({
      ...inputValue,
      [name]: value,
    });
  };

  <span class="hljs-keyword">const</span> handleError = <span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span>
    toast.error(err, {
      <span class="hljs-attr">position</span>: <span class="hljs-string">"bottom-left"</span>,
    });
  <span class="hljs-keyword">const</span> handleSuccess = <span class="hljs-function">(<span class="hljs-params">msg</span>) =&gt;</span>
    toast.success(msg, {
      <span class="hljs-attr">position</span>: <span class="hljs-string">"bottom-left"</span>,
    });

  <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-keyword">async</span> (e) =&gt; {
    e.preventDefault();
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> axios.post(
        <span class="hljs-string">"http://localhost:4000/login"</span>,
        {
          ...inputValue,
        },
        { <span class="hljs-attr">withCredentials</span>: <span class="hljs-literal">true</span> }
      );
      <span class="hljs-built_in">console</span>.log(data);
      <span class="hljs-keyword">const</span> { success, message } = data;
      <span class="hljs-keyword">if</span> (success) {
        handleSuccess(message);
        <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
          navigate(<span class="hljs-string">"/"</span>);
        }, <span class="hljs-number">1000</span>);
      } <span class="hljs-keyword">else</span> {
        handleError(message);
      }
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.log(error);
    }
    setInputValue({
      ...inputValue,
      <span class="hljs-attr">email</span>: <span class="hljs-string">""</span>,
      <span class="hljs-attr">password</span>: <span class="hljs-string">""</span>,
    });
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form_container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Login Account<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"email"</span>&gt;</span>Email<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"email"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{email}</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter your email"</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleOnChange}</span>
          /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"password"</span>&gt;</span>Password<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"password"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{password}</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter your password"</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleOnChange}</span>
          /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>
          Already have an account? <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">{</span>"/<span class="hljs-attr">signup</span>"}&gt;</span>Signup<span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ToastContainer</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Login;
</code></pre>
<h3 id="heading-how-to-handle-the-home-page-logic">How to Handle the Home Page Logic</h3>
<p>Copy and paste the following code snippet into the <code>Home.jsx</code> file located in the <code>pages</code> directory:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useNavigate } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> { useCookies } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-cookie"</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
<span class="hljs-keyword">import</span> { ToastContainer, toast } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-toastify"</span>;

<span class="hljs-keyword">const</span> Home = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> navigate = useNavigate();
  <span class="hljs-keyword">const</span> [cookies, removeCookie] = useCookies([]);
  <span class="hljs-keyword">const</span> [username, setUsername] = useState(<span class="hljs-string">""</span>);
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> verifyCookie = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">if</span> (!cookies.token) {
        navigate(<span class="hljs-string">"/login"</span>);
      }
      <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> axios.post(
        <span class="hljs-string">"http://localhost:4000"</span>,
        {},
        { <span class="hljs-attr">withCredentials</span>: <span class="hljs-literal">true</span> }
      );
      <span class="hljs-keyword">const</span> { status, user } = data;
      setUsername(user);
      <span class="hljs-keyword">return</span> status
        ? toast(<span class="hljs-string">`Hello <span class="hljs-subst">${user}</span>`</span>, {
            <span class="hljs-attr">position</span>: <span class="hljs-string">"top-right"</span>,
          })
        : (removeCookie(<span class="hljs-string">"token"</span>), navigate(<span class="hljs-string">"/login"</span>));
    };
    verifyCookie();
  }, [cookies, navigate, removeCookie]);
  <span class="hljs-keyword">const</span> Logout = <span class="hljs-function">() =&gt;</span> {
    removeCookie(<span class="hljs-string">"token"</span>);
    navigate(<span class="hljs-string">"/signup"</span>);
  };
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"home_page"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h4</span>&gt;</span>
          {" "}
          Welcome <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{username}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">h4</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{Logout}</span>&gt;</span>LOGOUT<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ToastContainer</span> /&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home;
</code></pre>
<p>Ensure that the styles below are copied into your <code>index.css</code> file:</p>
<pre><code class="lang-css">*,
<span class="hljs-selector-pseudo">::before</span>,
<span class="hljs-selector-pseudo">::after</span> {
  <span class="hljs-attribute">box-sizing</span>: border-box;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
}

<span class="hljs-selector-tag">label</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.2rem</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#656262</span>;
}

<span class="hljs-selector-tag">html</span>,
<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
}

<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">background</span>: <span class="hljs-built_in">linear-gradient</span>(
    <span class="hljs-number">90deg</span>,
    rgba(<span class="hljs-number">2</span>, <span class="hljs-number">0</span>, <span class="hljs-number">36</span>, <span class="hljs-number">1</span>) <span class="hljs-number">0%</span>,
    <span class="hljs-built_in">rgba</span>(<span class="hljs-number">143</span>, <span class="hljs-number">187</span>, <span class="hljs-number">204</span>, <span class="hljs-number">1</span>) <span class="hljs-number">35%</span>,
    <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">212</span>, <span class="hljs-number">255</span>, <span class="hljs-number">1</span>) <span class="hljs-number">100%</span>
  );
  <span class="hljs-attribute">font-family</span>: Verdana, Geneva, Tahoma, sans-serif;
}

<span class="hljs-selector-class">.form_container</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">2rem</span> <span class="hljs-number">3rem</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0.5rem</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">400px</span>;
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">8px</span> <span class="hljs-number">8px</span> <span class="hljs-number">24px</span> <span class="hljs-number">0px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">66</span>, <span class="hljs-number">68</span>, <span class="hljs-number">90</span>, <span class="hljs-number">1</span>);
}

<span class="hljs-selector-class">.form_container</span> &gt; <span class="hljs-selector-tag">h2</span> {
  <span class="hljs-attribute">margin-block</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">padding-block</span>: <span class="hljs-number">0.6rem</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">212</span>, <span class="hljs-number">255</span>, <span class="hljs-number">1</span>);
}

<span class="hljs-selector-class">.form_container</span> &gt; <span class="hljs-selector-tag">form</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">1.4rem</span>;
}

<span class="hljs-selector-class">.form_container</span> <span class="hljs-selector-tag">div</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">0.3rem</span>;
}

<span class="hljs-selector-class">.form_container</span> <span class="hljs-selector-tag">input</span> {
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.5rem</span>;
  <span class="hljs-attribute">border-bottom</span>: <span class="hljs-number">1px</span> solid gray;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.1rem</span>;
  <span class="hljs-attribute">outline</span>: none;
}

<span class="hljs-selector-class">.form_container</span> <span class="hljs-selector-tag">input</span><span class="hljs-selector-pseudo">::placeholder</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">0.9rem</span>;
  <span class="hljs-attribute">font-style</span>: italic;
}

<span class="hljs-selector-class">.form_container</span> <span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">212</span>, <span class="hljs-number">255</span>, <span class="hljs-number">1</span>);
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.6rem</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">cursor</span>: pointer;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0.3rem</span>;
}

<span class="hljs-selector-tag">span</span> <span class="hljs-selector-tag">a</span> {
  <span class="hljs-attribute">text-decoration</span>: none;
  <span class="hljs-attribute">color</span>: <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">212</span>, <span class="hljs-number">255</span>, <span class="hljs-number">1</span>);
}

<span class="hljs-selector-class">.home_page</span> {
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100vw</span>;
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#000</span>;
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">text-transform</span>: uppercase;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">3rem</span>;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">1rem</span>;
}

<span class="hljs-selector-class">.home_page</span> <span class="hljs-selector-tag">span</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">212</span>, <span class="hljs-number">255</span>, <span class="hljs-number">1</span>);
}

<span class="hljs-selector-class">.home_page</span> <span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">27</span>, <span class="hljs-number">73</span>, <span class="hljs-number">83</span>);
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">cursor</span>: pointer;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span> <span class="hljs-number">3rem</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">transition</span>: ease-in <span class="hljs-number">0.3s</span>;
  <span class="hljs-attribute">border</span>: none;
}

<span class="hljs-selector-class">.home_page</span> <span class="hljs-selector-tag">button</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">212</span>, <span class="hljs-number">255</span>, <span class="hljs-number">1</span>);
}


<span class="hljs-keyword">@media</span> <span class="hljs-keyword">only</span> screen <span class="hljs-keyword">and</span> (<span class="hljs-attribute">max-width:</span> <span class="hljs-number">1200px</span>){
  <span class="hljs-selector-class">.home_page</span>{
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.5rem</span>;
  }
  <span class="hljs-selector-class">.home_page</span> <span class="hljs-selector-tag">button</span> {
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.6rem</span> <span class="hljs-number">1rem</span>;
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.5rem</span>;
  }
}
</code></pre>
<p>I'll now quickly demonstrate everything you've learned in this article.</p>
<p><img src="https://i.imgur.com/1mQJVm7.gif" alt="1mQJVm7" width="600" height="400" loading="lazy"></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, you've learned how to use JWT for authentication and authorization, helping you build secure Node.js applications. </p>
<p>This guide can help you guard against security threats and prevent unauthorized access by implementing strong authentication and authorization procedures.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build Secure APIs with Flask and Auth0 ]]>
                </title>
                <description>
                    <![CDATA[ APIs are at the heart of modern development. They support all kinds of systems, from mobile, web, and desktop applications, to IoT devices and self-driving cars. They are a bridge between your clients and your application logic and storage.  This cen... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-secure-apis-with-flask-and-auth0/</link>
                <guid isPermaLink="false">66d039d433e91331eb22953b</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Auth0 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ authorization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flask Framework ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Juan Cruz Martinez ]]>
                </dc:creator>
                <pubDate>Wed, 08 Feb 2023 00:32:04 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/01/3.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>APIs are at the heart of modern development. They support all kinds of systems, from mobile, web, and desktop applications, to IoT devices and self-driving cars. They are a bridge between your clients and your application logic and storage. </p>
<p>This central access point to your application’s data raises the question: how can you provide access to the information to those who need it while denying access to unauthorized requests?</p>
<p>The industry has provided several protocols and best practices for securing APIs. Today we will focus on <a target="_blank" href="https://auth0.com/docs/authorization/protocols/protocol-oauth2?utm_source=freecodecamp?utm_source=freecodecamp&amp;utm_medium=sc&amp;utm_campaign=securing_flask">OAuth2</a>, one of the most popular options for authorizing clients into our APIs.</p>
<p>But how do we implement OAuth2? There are two ways to go about it:</p>
<ol>
<li>Do it yourself approach</li>
<li>Work with a safe 3rd party like <a target="_blank" href="https://auth0.com/?utm_source=freecodecamp&amp;utm_medium=sc&amp;utm_campaign=securing_flask">Auth0</a></li>
</ol>
<p>In this article, I will walk you through an implementation of OAuth2 for Python and <a target="_blank" href="https://flask.palletsprojects.com/">Flask</a> using Auth0 as our identity provider. But first, we are going to discuss the do-it-yourself approach.</p>
<h2 id="heading-why-not-build-your-own-authentication-and-authorization">Why Not Build Your Own Authentication and Authorization?</h2>
<p>For a few years now, I wanted to give back to the community that helped me so much by teaching me programming and helping me progress in my search for knowledge. I always thought that a great way to contribute was by having my own blog, a thing that I tried more than a few times and failed. </p>
<p>But where did I fail? Instead of focusing on writing, I tried to build my own blog engine because it’s in my nature. It’s what developers do. They love to build.</p>
<p>But why do I mention that here? Because many fall into the same trap when building APIs. Let me explain with an example.</p>
<p>Bob is a great developer, and he has this great idea for a ToDo app that can be the next big thing. Bob is very aware that for a successful implementation, users can only access their own data.</p>
<p>Here is bob’s application timeline:</p>
<ul>
<li>Sprint 0: Research ideas and start prototyping</li>
<li>Sprint 1: Build user table and login screen with API</li>
<li>Sprint 2: Add password reset screens and build all email templates</li>
<li>Sprint 3: Build, create and list ToDos screens</li>
<li>Sprint 4: MVP goes live</li>
<li>User feedback:<ul>
<li>Some users can’t log in due to a bug</li>
<li>Some users feel unsafe without 2-factor authentication</li>
<li>Some users don’t want to get yet another password. They prefer single sign-on with Google or Facebook.</li>
<li>…</li>
</ul>
</li>
</ul>
<p>Let’s talk about what happened. Bob spent the first few sprints not building his app but building the basic blocks, like logging in and out functionality, email notifications, and so on. This valuable time could have been spent differently, but what happens next is more concerning.</p>
<p>Bob’s backlog starts to fill in. Now, he needs to improvise a 2-factor authentication method, add single sign-on, and more non-product-related functions that could potentially delay his product.</p>
<p>And there’s still a big question to be answered: did Bob implement all the security mechanisms correctly? A critical error could expose all the user’s information to outsiders.</p>
<p>What Bob did is what I did with my blog many times. Sometimes, it's helpful to rely on 3rd parties if we want to get things done right.</p>
<p>Today, hackers and attacks have become so sophisticated that security is not a trivial factor anymore. It is a complicated system on its own, and it is often best to leave its implementation to experts – not only so it’s done right, but also so we can focus on what matters: building our applications and APIs.</p>
<h2 id="heading-how-to-set-up-a-free-auth0-identity-management-account">How to Set Up a Free Auth0 Identity Management Account</h2>
<p><a target="_blank" href="https://auth0.com/?utm_source=freecodecamp&amp;utm_medium=sc&amp;utm_campaign=securing_flask">Auth0</a> is a leading authentication and authorization provider, but let’s see how it can help Bob (or you) build a better app:</p>
<ol>
<li>It <a target="_blank" href="https://auth0.com/learn/finn-ai-saves-10-5-ongoing-engineering-time-auth0/?utm_source=freecodecamp&amp;utm_medium=sc&amp;utm_campaign=securing_flask">saves time</a></li>
<li>It’s <a target="_blank" href="https://auth0.com/security?utm_source=freecodecamp&amp;utm_medium=sc&amp;utm_campaign=securing_flask">secure</a></li>
<li>It has a <a target="_blank" href="https://auth0.com/pricing?utm_source=freecodecamp&amp;utm_medium=sc&amp;utm_campaign=securing_flask">free plan</a></li>
</ol>
<p>Time to get practical. First, make sure you have an Auth0 account. If not, you can create one <a target="_blank" href="https://auth0.com/signup/?utm_source=freecodecamp&amp;utm_medium=sc&amp;utm_campaign=securing_flask">here for free</a>.</p>
<h3 id="heading-create-a-new-auth0-api">Create a New Auth0 API</h3>
<p>There is still one more thing we have to do before we start coding. Head over to the <a target="_blank" href="https://manage.auth0.com/#/apis?utm_source=freecodecamp&amp;utm_medium=sc&amp;utm_campaign=securing_flask">APIs</a> section of your Auth0 dashboard and click on the “Create API” button. After that, fill in the form with your details. However, make sure you select <code>RS256</code> as the <code>Signing Algorithm</code>.</p>
<p>Your form should look like the following:</p>
<p><img src="https://lh5.googleusercontent.com/XccGez21ClEDsCECuKwiF_1AF5gj2OXXaJKEXVUOBFmxQ7Ci11a1g1O3cu_io185YbdnSJkAlu3dmP0pt6Ww-N6cPqQLTIeweSi2hNv4ototIkuSZhfiprjqcMrFhcMLaGkKfedkm8D0PR2IcjdLPGUChKS27wsiPMvqCsysQRJyGANVYc5Q5EbFdaFo" alt="Image" width="600" height="400" loading="lazy">
<em>Creating the API – image showing fields to fill out</em></p>
<p>The API details page opens after successfully creating an API. Keep that tab open, as it contains information we need to set up our application. If you close it, don’t worry, you can always access it again.</p>
<h2 id="heading-how-to-bootstrap-our-application">How to Bootstrap our Application</h2>
<p>Because we will focus on the security aspects only, we will take a few shortcuts when building our demo API. However, when developing <a target="_blank" href="https://livecodestream.dev/post/python-flask-api-starter-kit-and-project-layout/?utm_source=freecodecamp&amp;utm_medium=sc&amp;utm_campaign=securing_flask">actual APIs</a>, please follow <a target="_blank" href="https://auth0.com/blog/best-practices-for-flask-api-development/?utm_source=freecodecamp&amp;utm_medium=sc&amp;utm_campaign=securing_flask">best practices for Flask APIs</a>.</p>
<h3 id="heading-install-the-dependencies">Install the dependencies</h3>
<p>First, install the following dependencies for setting up Flask and authenticating users.</p>
<pre><code class="lang-shell">pipenv install flask python-dotenv python-jose flask-cors six
</code></pre>
<h3 id="heading-build-the-endpoints">Build the endpoints</h3>
<p>Our API will be straightforward. It will consist of only three endpoints, all of which, for now, will be publicly accessible. However, we will fix that soon. Here are our endpoints:</p>
<ul>
<li><code>/</code> (public endpoint)</li>
<li><code>/user</code> (requires a logged in user)</li>
<li><code>/admin</code> (only users of admin role)</li>
</ul>
<p>Let’s get to it:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask

app = Flask(__name__)

<span class="hljs-meta">@app.route("/")</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">index_view</span>():</span>
    <span class="hljs-string">"""
    Default endpoint, it is public and can be accessed by anyone
    """</span>
    <span class="hljs-keyword">return</span> jsonify(msg=<span class="hljs-string">"Hello world!"</span>)

<span class="hljs-meta">@app.route("/user")</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">user_view</span>():</span>
    <span class="hljs-string">"""
    User endpoint, can only be accessed by an authorized user
    """</span>
    <span class="hljs-keyword">return</span> jsonify(msg=<span class="hljs-string">"Hello user!"</span>)

<span class="hljs-meta">@app.route("/admin")</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">admin_view</span>():</span>
    <span class="hljs-string">"""
    Admin endpoint, can only be accessed by an admin
    """</span>
    <span class="hljs-keyword">return</span> jsonify(msg=<span class="hljs-string">"Hello admin!"</span>)
</code></pre>
<p>Very simple right? Let’s run it:</p>
<pre><code class="lang-shell">~ pipenv run flask run
* Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
</code></pre>
<p>And if we access our endpoint:</p>
<pre><code class="lang-shell">~ curl -i http://localhost:5000
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 23
Server: Werkzeug/2.0.1 Python/3.9.1
Date: Tue, 24 Jan 2023 21:24:57 GMT

{"msg":"Hello world!"}

~ curl -i http://localhost:5000/user
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 22
Server: Werkzeug/2.0.1 Python/3.9.1
Date: Tue, 24 Jan 2023 21:25:42 GMT

{"msg":"Hello user!"}

~ curl -i http://localhost:5000/admin
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 23
Server: Werkzeug/2.0.1 Python/3.9.1
Date: Tue, 24 Jan 2023 21:26:18 GMT

{"msg":"Hello admin!"}
</code></pre>
<h2 id="heading-how-to-secure-the-endpoints">How to Secure the Endpoints</h2>
<p>As we are using OAuth, we will authenticate requests by validating an access token in <a target="_blank" href="https://auth0.com/learn/json-web-tokens/?utm_source=freecodecamp&amp;utm_medium=sc&amp;utm_campaign=securing_flask">JWT format</a>. We'll send it to the API on each request as part of the HTTP headers.</p>
<h3 id="heading-auth0-configuration-variables">Auth0 configuration variables</h3>
<p>As mentioned in the previous section, our API needs to be aware and will require information from our Auth0 dashboard. So head back to your <a target="_blank" href="https://manage.auth0.com/#/apis?utm_source=freecodecamp&amp;utm_medium=sc&amp;utm_campaign=securing_flask">API details page</a>, and grab two different values.</p>
<p><strong>First, the API Identifier:</strong></p>
<p>This is the value required when the API is created. You can also get it from your API details page:</p>
<p><img src="https://lh5.googleusercontent.com/UffKcasZXNZmXldeB8nhDEjzmOPVao3PR6EUVPbtWzXStuDzcCw2kr5ztEnr0VlWCkBLbhleAM-D11Cv5Cv8fcII8m24D6TfEe4XfxWe8HXN1aNrF-dHeN05zeVeoNfQISWh-VPf0__x8uVfJPL3GGHYIC87utfrr6734Z9Wdk-9eJUApslcdUKOyoSh" alt="Image" width="600" height="400" loading="lazy">
<em>How to find the API identifier on the API details page</em></p>
<p><strong>Next, Auth0 domain:</strong></p>
<p>Unless you're using a custom domain, this value will be <a target="_blank"><code>[TENANT_NAME].auth0.com</code></a>, and you can grab it from the <code>Test</code> tab (make sure not to include <code>https://</code> and the last forward slash <code>/</code>).</p>
<p><img src="https://lh4.googleusercontent.com/cA63NdLr4AWOz2O3jTWBXTTqc7DrGOr1aPOIpNDRYl97-o84I_lX8KtotCm6hRWF06ai0RjiJzgTjS_zRlySKFAB-XO1w737N05i7-bC2-GZioOpcWuS5gaRoEnDL63gXnm5CyP6JOEQusRLQMF1sY_1vjfXtdMVIr5uCW1PMIpokH76lpMq2VFZSIyf" alt="Image" width="600" height="400" loading="lazy">
<em>Getting the Auth0 domain</em></p>
<p>Next, pass those values into variables so they can be used in the validation functions.</p>
<pre><code class="lang-python">AUTH0_DOMAIN = <span class="hljs-string">'YOUR-AUTH0-DOMAIN'</span>
API_IDENTIFIER = <span class="hljs-string">'API-IDENTIFIER'</span>
ALGORITHMS = [<span class="hljs-string">"RS256"</span>]
</code></pre>
<h3 id="heading-error-methods">Error methods</h3>
<p>During this implementation, we will need a way to throw errors when authentication fails. So we will use the following helpers for those needs:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AuthError</span>(<span class="hljs-params">Exception</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, error, status_code</span>):</span>
        self.error = error
        self.status_code = status_code

<span class="hljs-meta">@app.errorhandler(AuthError)</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">handle_auth_error</span>(<span class="hljs-params">ex</span>):</span>
    response = jsonify(ex.error)
    response.status_code = ex.status_code
    <span class="hljs-keyword">return</span> response
</code></pre>
<h3 id="heading-how-to-capture-the-jwt-token">How to capture the JWT token</h3>
<p>The first step to validate a user is to retrieve the JWT token from the HTTP headers. This is very simple, but there are a few things to keep in mind. Here is an example of it:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_token_auth_header</span>():</span>
    <span class="hljs-string">"""
    Obtains the Access Token from the Authorization Header
    """</span>
    auth = request.headers.get(<span class="hljs-string">"Authorization"</span>, <span class="hljs-literal">None</span>)
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> auth:
        <span class="hljs-keyword">raise</span> AuthError({<span class="hljs-string">"code"</span>: <span class="hljs-string">"authorization_header_missing"</span>,
                        <span class="hljs-string">"description"</span>:
                            <span class="hljs-string">"Authorization header is expected"</span>}, <span class="hljs-number">401</span>)

    parts = auth.split()

    <span class="hljs-keyword">if</span> parts[<span class="hljs-number">0</span>].lower() != <span class="hljs-string">"bearer"</span>:
        <span class="hljs-keyword">raise</span> AuthError({<span class="hljs-string">"code"</span>: <span class="hljs-string">"invalid_header"</span>,
                        <span class="hljs-string">"description"</span>:
                            <span class="hljs-string">"Authorization header must start with"</span>
                            <span class="hljs-string">" Bearer"</span>}, <span class="hljs-number">401</span>)
    <span class="hljs-keyword">elif</span> len(parts) == <span class="hljs-number">1</span>:
        <span class="hljs-keyword">raise</span> AuthError({<span class="hljs-string">"code"</span>: <span class="hljs-string">"invalid_header"</span>,
                        <span class="hljs-string">"description"</span>: <span class="hljs-string">"Token not found"</span>}, <span class="hljs-number">401</span>)
    <span class="hljs-keyword">elif</span> len(parts) &gt; <span class="hljs-number">2</span>:
        <span class="hljs-keyword">raise</span> AuthError({<span class="hljs-string">"code"</span>: <span class="hljs-string">"invalid_header"</span>,
                        <span class="hljs-string">"description"</span>:
                            <span class="hljs-string">"Authorization header must be"</span>
                            <span class="hljs-string">" Bearer token"</span>}, <span class="hljs-number">401</span>)

    token = parts[<span class="hljs-number">1</span>]
    <span class="hljs-keyword">return</span> token
</code></pre>
<h3 id="heading-how-to-validate-the-token">How to validate the token</h3>
<p>Having a token passed to our API is a good sign, but it doesn’t mean that it is a valid client. We need to check the token signature.</p>
<p>Since the logic to require authentication can be used for more than one endpoint, it would be important to abstract it and make it easily accessible for developers to implement. The best way to do this is by using <a target="_blank" href="https://book.pythontips.com/en/latest/decorators.html">decorators</a>.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">requires_auth</span>(<span class="hljs-params">f</span>):</span>
    <span class="hljs-string">"""
    Determines if the Access Token is valid
    """</span>
<span class="hljs-meta">    @wraps(f)</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">decorated</span>(<span class="hljs-params">*args, **kwargs</span>):</span>
        token = get_token_auth_header()
        jsonurl = urlopen(<span class="hljs-string">"https://"</span>+AUTH0_DOMAIN+<span class="hljs-string">"/.well-known/jwks.json"</span>)
        jwks = json.loads(jsonurl.read())
        unverified_header = jwt.get_unverified_header(token)
        rsa_key = {}
        <span class="hljs-keyword">for</span> key <span class="hljs-keyword">in</span> jwks[<span class="hljs-string">"keys"</span>]:
            <span class="hljs-keyword">if</span> key[<span class="hljs-string">"kid"</span>] == unverified_header[<span class="hljs-string">"kid"</span>]:
                rsa_key = {
                    <span class="hljs-string">"kty"</span>: key[<span class="hljs-string">"kty"</span>],
                    <span class="hljs-string">"kid"</span>: key[<span class="hljs-string">"kid"</span>],
                    <span class="hljs-string">"use"</span>: key[<span class="hljs-string">"use"</span>],
                    <span class="hljs-string">"n"</span>: key[<span class="hljs-string">"n"</span>],
                    <span class="hljs-string">"e"</span>: key[<span class="hljs-string">"e"</span>]
                }
        <span class="hljs-keyword">if</span> rsa_key:
            <span class="hljs-keyword">try</span>:
                payload = jwt.decode(
                    token,
                    rsa_key,
                    algorithms=ALGORITHMS,
                    audience=API_IDENTIFIER,
                    issuer=<span class="hljs-string">"https://"</span>+AUTH0_DOMAIN+<span class="hljs-string">"/"</span>
                )
            <span class="hljs-keyword">except</span> jwt.ExpiredSignatureError:
                <span class="hljs-keyword">raise</span> AuthError({<span class="hljs-string">"code"</span>: <span class="hljs-string">"token_expired"</span>,
                                <span class="hljs-string">"description"</span>: <span class="hljs-string">"token is expired"</span>}, <span class="hljs-number">401</span>)
            <span class="hljs-keyword">except</span> jwt.JWTClaimsError:
                <span class="hljs-keyword">raise</span> AuthError({<span class="hljs-string">"code"</span>: <span class="hljs-string">"invalid_claims"</span>,
                                <span class="hljs-string">"description"</span>:
                                    <span class="hljs-string">"incorrect claims,"</span>
                                    <span class="hljs-string">"please check the audience and issuer"</span>}, <span class="hljs-number">401</span>)
            <span class="hljs-keyword">except</span> Exception:
                <span class="hljs-keyword">raise</span> AuthError({<span class="hljs-string">"code"</span>: <span class="hljs-string">"invalid_header"</span>,
                                <span class="hljs-string">"description"</span>:
                                    <span class="hljs-string">"Unable to parse authentication"</span>
                                    <span class="hljs-string">" token."</span>}, <span class="hljs-number">401</span>)

            _request_ctx_stack.top.current_user = payload
            <span class="hljs-keyword">return</span> f(*args, **kwargs)
        <span class="hljs-keyword">raise</span> AuthError({<span class="hljs-string">"code"</span>: <span class="hljs-string">"invalid_header"</span>,
                        <span class="hljs-string">"description"</span>: <span class="hljs-string">"Unable to find appropriate key"</span>}, <span class="hljs-number">401</span>)
    <span class="hljs-keyword">return</span> decorated
</code></pre>
<p>The newly created <code>requires_auth</code> decorator, when applied to an endpoint, will automatically reject the request if no valid user can be authenticated.</p>
<h3 id="heading-how-to-require-an-authenticated-request-for-an-endpoint">How to require an authenticated request for an endpoint</h3>
<p>We are ready to secure our endpoints, let’s update the <code>user</code> and <code>admin</code> endpoints to utilize our decorator.</p>
<pre><code class="lang-python"><span class="hljs-meta">@app.route("/user")</span>
<span class="hljs-meta">@requires_auth</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">user_view</span>():</span>
    <span class="hljs-string">"""
    User endpoint, can only be accessed by an authorized user
    """</span>
    <span class="hljs-keyword">return</span> jsonify(msg=<span class="hljs-string">"Hello user!"</span>)

<span class="hljs-meta">@app.route("/admin")</span>
<span class="hljs-meta">@requires_auth</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">admin_view</span>():</span>
    <span class="hljs-string">"""
    Admin endpoint, can only be accessed by an admin
    """</span>
    <span class="hljs-keyword">return</span> jsonify(msg=<span class="hljs-string">"Hello admin!"</span>)
</code></pre>
<p>Our only change was adding <code>@required_auth</code> at the top of the declaration of each endpoint function, and with that we can test once again:</p>
<pre><code class="lang-shell">~ curl -i http://localhost:5000/user
HTTP/1.0 401 UNAUTHORIZED
Content-Type: application/json
Content-Length: 89
Server: Werkzeug/2.0.1 Python/3.9.1
Date: Tue, 24 Jan 2023 21:42:26 GMT

{"code":"authorization_header_missing","description":"Authorization header is expected"}

~ curl -i http://localhost:5000/admin
HTTP/1.0 401 UNAUTHORIZED
Content-Type: application/json
Content-Length: 89
Server: Werkzeug/2.0.1 Python/3.9.1
Date: Tue, 24 Jan 2023 21:42:42 GMT

{"code":"authorization_header_missing","description":"Authorization header is expected"}
</code></pre>
<p>As expected, we can’t access our endpoints as the authorization header is missing. But before we add one, let’s see if our public endpoint still works:</p>
<pre><code class="lang-shell">~ curl -i http://localhost:5000
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 23
Server: Werkzeug/2.0.1 Python/3.9.1
Date: Tue, 24 Jan 2023 21:43:55 GMT

{"msg":"Hello world!"}
</code></pre>
<p>Awesome, it works as expected.</p>
<h3 id="heading-how-to-test-it-out">How to test it out</h3>
<p>For testing our newly secured endpoints, we need to get a valid access token that we can pass to the request. We can do that directly on the <code>Test</code> tab on the API details page, and it’s as simple as copying a value from the screen:  </p>
<p><img src="https://lh5.googleusercontent.com/XCAWL5taQUs3_5qcAdukl9FP_aTVLya-jyS_4IivFW6JCAfX5d2hbPPCIV4PB8QgcuceQrzC__YYpWMQB1y8HT9AnKO01XH5rCiofvQJAmiAPnGF42FcJFxaVHTLLQcL9UpzFjYgan0Qasna69DlZ8AIkoATbqAtqtqibWUszhvakHZiytPNduTU7_Hb" alt="Image" width="600" height="400" loading="lazy">
<em>Copying the token for testing</em></p>
<p>Once we have the token we can change our curl request accordingly:</p>
<pre><code class="lang-shell">~ curl -i -H "Authorization: bearer [ACCESS_TOKEN]"  http://localhost:5000/user
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 22
Server: Werkzeug/2.0.1 Python/3.9.1
Date: Tue, 24 Jan 2023 22:17:06 GMT

{"msg":"Hello user!"}
</code></pre>
<p>Please remember to replace <code>[ACCESS_TOKEN]</code> with the value you copied from the dashboard.</p>
<p>It works! But we still have some work to do. Even though our <code>/admin</code> endpoint is secured, it can be accessed by any user:</p>
<pre><code class="lang-shell">~ curl -i -H "Authorization: bearer [ACCESS_TOKEN]"  http://localhost:5000/admin
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 23
Server: Werkzeug/2.0.1 Python/3.9.1
Date: Tue, 24 Jan 2023 22:21:09 GMT

{"msg":"Hello admin!"}
</code></pre>
<h3 id="heading-role-based-access-control">Role-based access control</h3>
<p>For role-based access control there’s a few things we need to do:</p>
<ol>
<li>Create permissions for the API</li>
<li>Enable adding permissions to the JWT for the API</li>
<li>Update the code</li>
<li>Test with users</li>
</ol>
<p>The first 2 points are very well explained in the <a target="_blank" href="https://auth0.com/docs/authorization/rbac/auth-core-features?utm_source=freecodecamp&amp;utm_medium=sc&amp;utm_campaign=securing_flask">Auth0 docs</a>, so just make sure you add the corresponding permissions on your API. </p>
<p>Next, we need to update the code. We need a function to check if a given permission exists in the access token and return <code>True</code> if it does and <code>False</code> if it does not:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">requires_scope</span>(<span class="hljs-params">required_scope</span>):</span>
    <span class="hljs-string">"""
    Determines if the required scope is present in the Access Token
    Args:
        required_scope (str): The scope required to access the resource
    """</span>
    token = get_token_auth_header()
    unverified_claims = jwt.get_unverified_claims(token)
    <span class="hljs-keyword">if</span> unverified_claims.get(<span class="hljs-string">"scope"</span>):
            token_scopes = unverified_claims[<span class="hljs-string">"scope"</span>].split()
            <span class="hljs-keyword">for</span> token_scope <span class="hljs-keyword">in</span> token_scopes:
                <span class="hljs-keyword">if</span> token_scope == required_scope:
                    <span class="hljs-keyword">return</span> <span class="hljs-literal">True</span>
    <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>
</code></pre>
<p>And lastly, it can be used as follows:</p>
<pre><code class="lang-python"><span class="hljs-meta">@app.route("/admin")</span>
<span class="hljs-meta">@requires_auth</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">admin_view</span>():</span>
    <span class="hljs-string">"""
    Admin endpoint, can only be accessed by an admin
    """</span>
    <span class="hljs-keyword">if</span> requires_scope(<span class="hljs-string">"read:admin"</span>):
        <span class="hljs-keyword">return</span> jsonify(msg=<span class="hljs-string">"Hello admin!"</span>)

    <span class="hljs-keyword">raise</span> AuthError({
        <span class="hljs-string">"code"</span>: <span class="hljs-string">"Unauthorized"</span>,
        <span class="hljs-string">"description"</span>: <span class="hljs-string">"You don't have access to this resource"</span>
    }, <span class="hljs-number">403</span>)
</code></pre>
<p>Now, only users with the permission <code>read:admin</code> can access our admin endpoint.</p>
<p>In order to test your final implementation, you can follow the steps detailed on <a target="_blank" href="https://auth0.com/docs/quickstart/backend/python/02-using#obtaining-an-access-token?utm_source=freecodecamp&amp;utm_medium=sc&amp;utm_campaign=securing_flask">obtaining an access token</a> for a given user. </p>
<p>You can also use the Auth0 Dashboard to test permissions, but that is outside the scope of this article. If you would like to learn more about it, read <a target="_blank" href="https://auth0.com/blog/permission-based-security-aspnet-webapi/#Testing-Permissions">here</a>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Today we learned how to secure a Flask API. We explored the do-it-yourself path, and we built a secure API with three levels of access – public access, private access and privately-scoped access.</p>
<p>There’s so much more that Auth0 can do for your APIs and also for your client applications. Today we just scratched the surface, and it’s up to you and your team when working with real-life scenarios to explore all the potential of their services.</p>
<p>The full code is available on <a target="_blank" href="https://gist.github.com/bajcmartinez/5062aa41ccbe2df1bbf4f1a9b95bd085">GitHub</a>.</p>
<p>Thanks for reading! If you like my teaching style, you can <a target="_blank" href="https://livecodestream.dev/newsletter/">Subscribe to my weekly newsletter</a> for developers and builders and get a weekly email with relevant content<em>.</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Sign and Validate JSON Web Tokens – JWT Tutorial ]]>
                </title>
                <description>
                    <![CDATA[ A JSON Web Token, or JWT, is an open standard for securely creating and sending data between two parties, usually a client and a server. If you've ever signed in to a site like freeCodeCamp with your Google or GitHub account, there's a good chance th... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-sign-and-validate-json-web-tokens/</link>
                <guid isPermaLink="false">66ac880a2dd2c39dc134e0bf</guid>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ authorization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JWT ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Kristofer Koishigawa ]]>
                </dc:creator>
                <pubDate>Fri, 09 Dec 2022 10:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/01/shubham-dhage-gC_aoAjQl2Q-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>A JSON Web Token, or JWT, is an open standard for securely creating and sending data between two parties, usually a client and a server.</p>
<p>If you've ever signed in to a site like freeCodeCamp with your Google or GitHub account, there's a good chance that you're already using a JWT.</p>
<p>In this article, we'll go over how JWTs are used, then dig into what JWTs are, and how they can securely transmit data through the signature and validation process.</p>
<h2 id="heading-how-jwts-are-used">How JWTs Are Used</h2>
<p>JWTs are usually used to manage user sessions on a website. While they're an important part of the token based authentication process, JWTs themselves are used for authorization, not authentication.</p>
<p>Here's a good overview of how token based authentication works:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/token-based-authentication.jpg" alt="A diagram showing the flow for token based authentication with JWT." width="600" height="400" loading="lazy">
<em><a target="_blank" href="https://hackernoon.com/using-session-cookies-vs-jwt-for-authentication-sd2v3vci">Source</a></em></p>
<p>When you sign in to a site with a username and password, or with a third party method like Google, you're proving who you are with those sensitive details or access. This process is called <strong>authentication</strong>.</p>
<p>Once you're signed in, the site's server sends back a JWT that allows you access to things like your settings page, shopping cart, and so on. This process is called <strong>authorization</strong>.</p>
<p>You send your JWT to the server with each request. When the server receives it, it generates a signature using some data from your JWT, verifies it, and if your JWT is valid, it sends back a response.</p>
<h2 id="heading-what-are-jwts">What are JWTs?</h2>
<p>At their core, JWTs are just bits of encoded JSON data with a cryptographic signature at the end.</p>
<p>Here's an example of a JWT:</p>
<pre><code>eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IlF1aW5jeSBMYXJzb24iLCJpYXQiOjE1MTYyMzkwMjJ9.WcPGXClpKD7Bc1C0CCDA1060E2GGlTfamrd8-W0ghBE
</code></pre><p>Each JWT is made up of three segments, each separated by a dot (<code>.</code>). These three segments are the header, payload, and signature.</p>
<p>If you copy and paste that JWT into the <a target="_blank" href="https://jwt.io/">JWT.io Debugger</a>, you can see the decoded versions of those three segments.</p>
<h3 id="heading-header-segment">Header Segment</h3>
<p>The header segment of a JWT contains information about the algorithm and token type.</p>
<p>Here's the header segment of the example JWT token above:</p>
<pre><code>eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
</code></pre><p>The header segment is base 64 URL encoded, and decodes to the following JSON object:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"alg"</span>: <span class="hljs-string">"HS256"</span>,
  <span class="hljs-attr">"typ"</span>: <span class="hljs-string">"JWT"</span>
}
</code></pre>
<p><code>"alg"</code> is the type of algorithm used in the last segment, the cryptographic signature. In this case, the HMAC SHA256 algorithm is used, though RSA is also common.</p>
<p><code>"typ"</code> is the type of token the segmented string is, which in this case is JWT.</p>
<h3 id="heading-payload-segment">Payload Segment</h3>
<p>The payload segment of a JWT contains registered claims or identifying information, usually for a user.</p>
<p>Here's the payload segment of the example JWT token above:</p>
<pre><code>eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IlF1aW5jeSBMYXJzb24iLCJpYXQiOjE1MTYyMzkwMjJ9
</code></pre><p>The payload segment is also base 64 URL encoded, and decodes to the following JSON object:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"sub"</span>: <span class="hljs-string">"1234567890"</span>,
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Quincy Larson"</span>,
  <span class="hljs-attr">"iat"</span>: <span class="hljs-number">1516239022</span>
}
</code></pre>
<p>Since JWTs are usually used as part of the authentication method for sites, the payload segment usually contains identifying information for a user. These claims fall into three categories: registered, public, and private.</p>
<p>Registered claims are a set of predefined claims defined <a target="_blank" href="https://www.rfc-editor.org/rfc/rfc7519#section-4.1">here</a> that are optional, but recommended when using JWTs.</p>
<p>Public claims are optional claims, usually from the <a target="_blank" href="https://www.iana.org/assignments/jwt/jwt.xhtml">IANA JSON Web Token Registry</a>.</p>
<p>Private claims are optional, and are any claims that don't fall under the registered or public claims categories.</p>
<p><code>"sub"</code> is the subject of the JWT, and is usually a unique identifying string for a user in an application, usually an email address, username, or id. Subjects are registered claims.</p>
<p><code>"name"</code> is the full name of the user who was issued the JWT, and is a public claim.</p>
<p><code>"iat"</code> is the "issued at" date for the token, and is a registered claim.</p>
<h3 id="heading-signature-segment">Signature Segment</h3>
<p>The signature segment of a JWT contains the cryptographic signature of the token.</p>
<p>Here's the signature segment of the example JWT token above:</p>
<pre><code>WcPGXClpKD7Bc1C0CCDA1060E2GGlTfamrd8-W0ghBE
</code></pre><p>The signature segment is made up of the base 64 URL encoded header and payload segments, a secret (usually the contents of a key in a signing algorithm), and hashed using the algorithm defined in the header segment:</p>
<pre><code>HMACSHA256(
  base64UrlEncode(header) + <span class="hljs-string">"."</span> +
  base64UrlEncode(payload),
  your<span class="hljs-number">-256</span>-bit-secret
)
</code></pre><p>The signature helps ensure that the data in the header and payload segments haven't been tampered with, and the JWT can be trusted.</p>
<p>However, it's important to note that the cryptographic signature at the end of the JWT is just for validation. It doesn't encrypt any data in the header or payload segments of the token. So you should never send sensitive information like a user's password in a JWT – everything in the header and payload can and should be public.</p>
<h4 id="heading-how-to-validate-jwt-signatures">How to Validate JWT Signatures</h4>
<p>The exact method for validating a signature depends on the algorithm defined in the header segment and used to generate the signature itself.</p>
<p>For the HS256 signing algorithm, a private key is shared between two entities, say your application's server and an authentication server. This private key is used both to generate signatures for outgoing JWTs, and to validate signatures from incoming JWTs.</p>
<p>When your authentication server receives an incoming JWT, it uses the incoming JWT's header and payload segments and the shared private key to generate a signature.</p>
<p>If the signature matches, then your application knows that the incoming JWT can be trusted.</p>
<p>Another popular signing algorithm is RS256, which uses public and private key pairs to validate signatures. This is similar to the system used for SSH and SSL.</p>
<p>If you'd like to read more about how RS256 works, check out this article:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.freecodecamp.org/news/understanding-encryption-algorithms/#rsa">https://www.freecodecamp.org/news/understanding-encryption-algorithms/#rsa</a></div>
<h2 id="heading-other-helpful-tutorials">Other Helpful Tutorials</h2>
<p>If you'd like to learn more about JWTs and how to use them in applications, check out these tutorials:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.freecodecamp.org/news/what-are-json-web-tokens-jwt-auth-tutorial/">https://www.freecodecamp.org/news/what-are-json-web-tokens-jwt-auth-tutorial/</a></div>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.freecodecamp.org/news/learn-to-implement-user-authentication-in-node-apps-using-passport-js/">https://www.freecodecamp.org/news/learn-to-implement-user-authentication-in-node-apps-using-passport-js/</a></div>
<h2 id="heading-thanks-for-reading">Thanks for Reading</h2>
<p>If you found this article on JWTs helpful, consider sharing it so more people can benefit from it.</p>
<p>Also, feel free to reach out on <a target="_blank" href="https://twitter.com/kriskoishigawa">Twitter</a> and let me know what you think.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ AWS Identity and Access Management (IAM) – Explained With an Analogy ]]>
                </title>
                <description>
                    <![CDATA[ AWS IAM (Identity and Access Management) gives you control over who can access your AWS services and resources based on some predefined permissions. The two keywords here are “who” and “permissions”. “Who” refers to a specific identity, which can be ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/aws-iam-explained/</link>
                <guid isPermaLink="false">66d45e08d1ffc3d3eb89ddbd</guid>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ authorization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ AWS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ IAM ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Daniel Adetunji ]]>
                </dc:creator>
                <pubDate>Wed, 16 Nov 2022 18:51:48 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/11/Slide1.JPG" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>AWS IAM (Identity and Access Management) gives you control over <strong>who</strong> can access your AWS services and resources based on some predefined <strong>permissions</strong>.</p>
<p>The two keywords here are “who” and “permissions”. “Who” refers to a specific identity, which can be a <strong>user</strong>, <strong>group</strong> or <strong>role</strong>. “permissions” refer to the <strong>policies</strong> that are attached to an identity. These permissions either allow or deny access to a resource.</p>
<p>IAM is the AWS way of authenticating and authorising identities. Authentication is not, however, the same as authorisation. Authentication is concerned with the “<strong>who</strong>” while authorisation is concerned with the “<strong>permissions</strong>”.</p>
<h2 id="heading-the-difference-between-authentication-and-authorisation">The Difference Between Authentication and Authorisation</h2>
<p>Authentication is when an identity proves it is what/who it says it is. Authorisation, on the other hand, is proving that you have the permissions to access a resource.</p>
<p>To fully understand the difference, consider the following analogy. You need to be both authenticated and authorised in order to board a flight. Authentication is done with your passport or ID, where it is checked to ensure that the photo in your passport matches your face. This proves that you are who you say you are.</p>
<p>After you have been authenticated, you need to prove that you have the permission to take a specific flight. This is done with your boarding pass.</p>
<p>Both authentication and authorisation need to be carried out before you can board a flight. Similarly, both need to be carried out before you can access AWS resources.</p>
<p>You can <a target="_blank" href="https://www.freecodecamp.org/news/whats-the-difference-between-authentication-and-authorisation/">read more about authorisation vs authentication here</a>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/image-70.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Authentication &amp; authorisation are not the same</em></p>
<p>IAM users, groups, and roles are concerned with authentication – that is, proving that you are who you say you are. They are like passports that get you through security in an airport.</p>
<p>Without a boarding pass however, you cannot board a plane. The IAM policy is like a boarding pass, in that it grants or denies access to specific resources.</p>
<h2 id="heading-what-are-iam-users">What are IAM Users?</h2>
<p>This is any identity (humans or an application) that requires long term access to AWS resources. These entities make requests to IAM to get authenticated before any interaction with AWS resources is allowed the happen.</p>
<p>Authentication is done using a username/password combination for humans accessing AWS through the console, or through access keys for an application or a human accessing AWS through the command line interface.</p>
<h2 id="heading-what-are-iam-groups">What are IAM Groups?</h2>
<p>IAM users can be placed in an IAM group. IAM groups makes it easier to organise a large number IAM users and apply permissions on a group level instead of an individual level. This is because the latter does not scale for a large number of users.</p>
<p>Imagine you have a team that consists of developers, architects, admin staff, DevOps engineers, live support and testers. Each of these teams has 10 people, for a total of 60 people.</p>
<p>Instead of setting permission policies for 60 people individually, you can put IAM users into their respective groups and apply permissions on a group level. This makes it easier to organise permissions and also easier to scale as your team grows.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/image-72.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>IAM groups can be created for separate teams</em></p>
<p>There are no login credentials for IAM groups. Also, a user can belong to multiple groups, so for example, an IAM user that is in the DevOps group can also be in the live support group. This maps neatly to the real world where a DevOps engineer can also be in live support.</p>
<h2 id="heading-what-are-iam-roles">What are IAM Roles?</h2>
<p>IAM roles are used to grant <strong>temporary access</strong> to multiple identities. These identities could be humans external to AWS accessing your services, IAM users, or applications.</p>
<p>These identities assume the role temporarily, and any permission policies attached to the role are by proxy applied to the identity assuming that role.</p>
<p>IAM roles are important because AWS has hard limits on the number of IAM users (<a target="_blank" href="https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-quotas.html">currently 5000</a>).</p>
<h3 id="heading-trust-policies-vs-permission-policies">Trust policies vs permission policies</h3>
<p>IAM policies that are attached to roles come in two flavours – trust policy and permission policy.</p>
<p>The trust policy controls which identity (for example IAM users, AWS resources like EC2 instances, anonymous entities) can assume that role. Once a role is assumed by an identity, AWS issues it <a target="_blank" href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html">Temporary Security Credentials</a>.</p>
<p>You can think of the trust policy as how AWS authenticates an IAM role to ensure that only the identity that is allowed to assume the role can assume the role – that is, that an identity has proved that it is who/what it says it is.</p>
<p>But there is a catch. With trust policies, this authentication only works for a period of time. Once that time has elapsed, the identity needs to re-authenticate and get new Temporary Security Credentials.</p>
<p>The permission policy is relatively straightforward: it defines the permissions that the role has, which, by proxy, defines the permissions that the identity assuming that role will have.</p>
<p>IAM roles are a relatively difficult concept to grasp, so if you don’t quite understand it yet, please read on and it will become clearer.</p>
<h2 id="heading-how-iam-policies-work">How IAM Policies Work</h2>
<p>IAM Policies are attached to identities, so users, groups, or roles. IAM policies can also be attached to some AWS resources. These types of policies are called <a target="_blank" href="https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_identity-vs-resource.html">resource based policies</a>.</p>
<p>IAM policies are JSON documents, consisting of one or more statements that grant or deny access to AWS resources.</p>
<p>The IAM policy below shows how permissions are granted to an identity to read and write from an S3 bucket.</p>
<pre><code class="lang-python">{
    <span class="hljs-string">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>,
    <span class="hljs-string">"Statement"</span>: [
        {
            <span class="hljs-string">"Sid"</span>: <span class="hljs-string">"ListObjectsInBucket"</span>,
            <span class="hljs-string">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-string">"Action"</span>: [<span class="hljs-string">"s3:ListBucket"</span>],
            <span class="hljs-string">"Resource"</span>: [<span class="hljs-string">"arn:aws:s3:::bucket-name"</span>]
        },
        {
            <span class="hljs-string">"Sid"</span>: <span class="hljs-string">"AllObjectActions"</span>,
            <span class="hljs-string">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-string">"Action"</span>: <span class="hljs-string">"s3:*Object"</span>,
            <span class="hljs-string">"Resource"</span>: [<span class="hljs-string">"arn:aws:s3:::bucket-name/*"</span>]
        }
    ]
}
</code></pre>
<ul>
<li><p><code>Sid</code> stands for statement ID, an optional field that lets the reader quickly identify what a statement does.</p>
</li>
<li><p><code>Effect</code> can be either allow or deny</p>
</li>
<li><p><code>Action</code> refers to what action are you trying to perform. Format is <strong>service:operation</strong>.</p>
</li>
<li><p><code>Resource</code> refers to which resource are you interacting with. Typically you'll use <a target="_blank" href="https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html">ARN</a> (Amazon Resource Name) which uniquely identify AWS resources.</p>
</li>
</ul>
<p>By default, all requests are implicitly denied unless a policy explicitly has an “allow” as is the case in the example above.</p>
<p>This principle of least privilege ensures that an identity cannot use a resource unless they are explicitly granted the permission to do so.</p>
<h2 id="heading-bringing-it-all-together-how-iam-works">Bringing it All Together – How IAM Works</h2>
<p>Consider a pizza restaurant. It will have some full time employees – like chefs, waiters and cleaners. It may also have some part time chefs to help during peak demand on evenings and weekends. If the restaurant is any good, it will also have customers who can eat in and take out.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/image-73.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>IAM restaurant analogy</em></p>
<p>To draw an analogy with AWS IAM, the full time employees are like IAM users. They require long term access to the restaurant’s resources as shown above. These users will all belong to different groups – the waiters, chef, and cleaners group (that is, all waiters, for example, will have the same job title of “waiter”).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/image-74.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>IAM restaurant analogy</em></p>
<p>How are the restaurant’s employees authenticated? How do we know that they are who they say they are? Name badges with a picture will do the job. This can also show their title which is analogous to the IAM group that they belong to.</p>
<p>The permission policies that define what resources the restaurant’s employees can access are applied on the group level, since every waiter, chef and cleaner will have the same permissions. This may not be true in reality, as the head chef for example may have privileged access. But for simplicity, let's assume it is true.</p>
<p>How does the restaurant manager control who has access to what resources? Doors with locks will do just fine. Keys act as a policy as they control access to parts of the restaurant.</p>
<p>An identical set will be given to all waiters, since waiters will need the same level of access to the food/drink storage room, kitchen, and seating area.</p>
<p>The same logic will apply to the other full time employees, where the appropriate set of keys are handed out so that they can use the restaurant’s resources as needed.</p>
<p>Giving keys to the restaurant employees is analogous to attaching a policy to an IAM user or group. Without the keys, the employees cannot access parts of the restaurant.</p>
<p>Similarly in AWS, without policies that explicitly allow an action, requests cannot be made to AWS resources. The default state in both AWS and our restaurant analogy is an implicit deny when trying to access resources.</p>
<p>The part time employees, like a temporary chef for example, and the customers, don’t need long term access to resources but will need short term access, analogous to IAM roles.</p>
<p>The part time employees can only work during a short window – say during evenings on the weekend. Outside of this time, they don’t have permissions to use the restaurant’s resources.</p>
<p>This part time chef does not have to be the same person. It could be a different person every week, unlike the full time employees that have specific identities.</p>
<p>A part time chef will therefore <strong>assume</strong> the role of a chef and get a <strong>temporary</strong> badge that they keep for the duration of their shift. This is analogous to an entity assuming an IAM role that has a policy attached to it and getting Temporary Security Credentials that will expire after some time.</p>
<p>Again, the policy here is the set of keys that grant permission to parts of the restaurant while the Temporary Security Credential is the temporary badge used to authenticate the chef.</p>
<p>Similarly, the customers are analogous to IAM roles for two reasons. First, they only require temporary access to the restaurant. Second, and perhaps more importantly, a successful restaurant will have tens of thousands to hundreds of thousands of unique customers over its lifetime.</p>
<p>Having a large number of unidentified entities is a perfect use case for IAM roles. Recall that with AWS, there is a hard limit of 5000 for the number of IAM users you can have. If there is a use case where the number of IAM users required will exceed this 5000 limit, using IAM roles is your only option around this.</p>
<p>Just like how IAM roles are assumed, the customer first needs to order something to prove that they are a customer and can assume the role of a customer.</p>
<p>After the customer role is assumed, the permissions policy attached to the customer role is then applied to the customer as well. Customers have permissions to only use some resources like the seating area and the toilet.</p>
<p>To keep the analogy realistic, access to the toilet is controlled by entering a passcode which changes every day, thus ensuring that the access is temporary. This passcode is analogous to the policy attached to the customer role that grants temporary access to the toilet.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/image-75.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-example-use-case-of-iam-roles">Example Use Case of IAM Roles</h2>
<p>Consider the following very simple architecture: an EC2 instance running an application that needs full access to an S3 bucket.</p>
<p>How would you give the EC2 instance the permission to read and write objects from an S3 bucket? This is explained in the diagram below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/image-77.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Attaching a policy to an IAM role and letting an EC2 instance assume that role</em></p>
<ol>
<li><p>Create an IAM role for your EC2 instance</p>
</li>
<li><p>Attach an IAM policy to the role that gives full access to the S3 bucket</p>
</li>
<li><p>Let the EC2 instance assume the role</p>
</li>
</ol>
<p>The IAM policy for full S3 access mentioned in step #2 is:</p>
<pre><code class="lang-python">{
    <span class="hljs-string">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>,
    <span class="hljs-string">"Statement"</span>: [
        {
            <span class="hljs-string">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-string">"Action"</span>: [
                <span class="hljs-string">"s3:*"</span>,
                <span class="hljs-string">"s3-object-lambda:*"</span>
            ],
            <span class="hljs-string">"Resource"</span>: <span class="hljs-string">"*"</span>
        }
    ]
}
</code></pre>
<p>You can now read from and write to the S3 bucket. Notice that in the policy above, it doesn’t specify any ARN, but just says “*” for the resource. This means all S3 buckets. If that is what you want, then this policy is fine. But if you want to specify a single bucket, then you need to give the bucket ARN.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Understanding IAM and the difference between users, roles, groups and how policies work gives you a strong foundation on which you can architect and build secure solutions with AWS.</p>
<p>Thank you for reading!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Authentication vs Authorization – What's the Difference? ]]>
                </title>
                <description>
                    <![CDATA[ When you're starting out in web development, you'll likely hear the terms authentication and authorization all the time. And it doesn't help that they're both usually abbreviated 'auth', so it's very easy to get the two confused. In this article, you... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/whats-the-difference-between-authentication-and-authorisation/</link>
                <guid isPermaLink="false">66bb88a53e3fa59ecfecb852</guid>
                
                    <category>
                        <![CDATA[ Application Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ authorization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ information security ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Grant Riordan ]]>
                </dc:creator>
                <pubDate>Thu, 29 Sep 2022 17:45:49 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/09/Background1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>When you're starting out in web development, you'll likely hear the terms authentication and authorization all the time. And it doesn't help that they're both usually abbreviated 'auth', so it's very easy to get the two confused.</p>
<p>In this article, you will learn:</p>
<ul>
<li>The differences between authentication and authorization</li>
<li>How each of these processes work</li>
<li>Examples of authorization and authentication in everyday life.</li>
</ul>
<p>‌‌‌‌Ok, let's get started.</p>
<h2 id="heading-what-is-authentication">What is Authentication?</h2>
<p>Authentication is the the process of <strong>verifying</strong> the credentials a user provides with those stored in a system to <strong>prove</strong> the user is who they say they are. If the credentials match, then you grant access. If not, you deny it.</p>
<h3 id="heading-methods-of-authentication">Methods of Authentication</h3>
<h4 id="heading-single-factor-authentication">Single Factor authentication:</h4>
<p>This is often used as the authentication process for lower risk systems. You only need a single factor to authenticate, with the most common being a password, so it's more vulnerable to phishing attacks and key loggers. </p>
<p>In addition to this, a recent <a target="_blank" href="https://dataprot.net/statistics/password-statistics/">article</a> by DataProt showed that  78% of Gen-Z people utilize the same password for multiple services. This means that if an attacker gained access to one user account, they have a high probability of gaining access to others by simply using the same password.</p>
<h4 id="heading-2-factor-authentication">2-Factor Authentication:</h4>
<p>This method is more secure, as it comprises two factors of authentication – typically something you know, for example username and password , plus something you have / own, for example a phone SMS or a security token. </p>
<p>For 2-factor authentication, you would enter a one-time SMS password sent to your device, or perhaps a linked authenticator app code and provide an ever-changing access code.</p>
<p>As you can imagine, this is a lot more secure than simply entering a password, or a single authentication credential. You would need to know the login credentials, as well as have access to the physical device for the second part.</p>
<p>2-factor authentication has become very common amongst online services in recent years, and with many large companies it is the default authentication method. Many require that you setup 2-factor auth in order to even utilize the service.</p>
<h4 id="heading-multi-factor-authentication">Multi-Factor Authentication:</h4>
<p>Going one step further to make your authentication process even more secure is having 3 or more factors. This form of authentication usually works on the premise of:</p>
<ul>
<li>something you know (username + password or a username + security question and answer)</li>
<li>something you have (mobile phone sms, authenticator app, USB key)</li>
<li>something you are (like a fingerprint / face recognition)</li>
</ul>
<p>For these reasons, multi-factor authentication offers the most protection, as you would need to compromise multiple factors, and these factors are a lot more difficult to "hack" or replicate.   </p>
<p>The downside to this method of authentication, and the reason it's not utilized in many average systems, is it can be cumbersome to setup and maintain. So the data / system you're protecting really has to justify the need for such security.</p>
<h2 id="heading-so-how-much-information-do-you-need-to-authenticate">So, How Much Information Do You Need to Authenticate?</h2>
<p>This question comes up at many security architecture meetings, and the answer is "<em>it depends</em>".</p>
<p>It is not unusual for companies to combine various authentication methods to increase security based on the nature of application.</p>
<p>For example, take a banking app. It contains very sensitive information, and could have a huge financial and reputational impacts should it be obtained by the wrong person. The bank may combine personal questions to be answered, along with a customer number and complex password.</p>
<p>On the other hand, for a social media site, you might only require a username and password, which is then checked and verified before allowing access.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/Auth_Process-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>It's all about the level of risk involved and what information someone can access once they're in the application. This helps determine the level of authentication you need.</p>
<p>If you or your team underestimates the level of authentication your app needs, you could be prosecuted for not securing the data within your system adequately. So companies employee security specialists to advise on best practices and appropriate solutions.</p>
<h2 id="heading-how-does-authentication-work-in-the-real-world">How Does Authentication Work in the Real World?</h2>
<p>Let's take an example of a social media account. You choose your favorite social media site (which is hosted on a server). The server will ask you to provide credentials to access the site via a sign in page. Here you would type in your username and password that you used when creating the account.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/server-process-2.png" alt="Image" width="600" height="400" loading="lazy">
<em>Image showing the authentication process</em></p>
<p>These details are then sent to the server, and the authentication process begins. The details you provided are verified and checked in the server's database, and if they match the details on record you are authenticated. Then you're provided with a form of identification data, for example a cookie or Json Web Token (JWT token).</p>
<p>Success! You have accessed the site and are given entry.</p>
<p>You can learn more about JWT tokens in another FreeCodeCamp article by Beau Carnes <a target="_blank" href="https://www.freecodecamp.org/news/what-are-json-web-tokens-jwt-auth-tutorial/">here</a>.</p>
<p>Next, let's look at authorization.</p>
<h2 id="heading-what-is-authorization">What is Authorization?</h2>
<p>Authorization, is the process of verifying that you're <strong>allowed</strong> to access an area of an application or perform specific actions, based on certain criteria and conditions put in place by the application. You may also hear it called access control or privilege control.</p>
<p>Authorization can either grant or deny permission to carry out tasks, or access areas of an application.</p>
<p>Let's look at an example:</p>
<p>We've gained access to the social media site, but what we're allowed to do there depends on what we're authorized to to do.</p>
<p>If we try to access someone's profile that we're not friends with (they've not accepted our connection request), we're not <strong>authorized</strong> to view their profile. This means that we are denied permission to view their shared posts.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/auth-process2-1.png" alt="Basic Authorisation Process" width="600" height="400" loading="lazy">
<em>Image of authorization flow</em></p>
<h3 id="heading-how-to-implement-authorization">How to Implement Authorization</h3>
<p>There are many ways you can implement authorization depending on the frameworks you are using.</p>
<p>Within the .NET framework, for example, you could use role-based access control, or claims-based access control.</p>
<p>Role-based access control is centered around the ideology that each user within your system is assigned a role. These roles have predefined permissions associated with them. Being granted a role means that user will automatically inherit all these permissions. The roles are assigned at time of user creation and setup.</p>
<p>The endpoint or site simply then checks if the current logged-in user has the role of Admin when attempting to access the admin area.</p>
<p>The downside to this approach is that sometimes users are granted too many permissions that they don't need or shouldn't have.</p>
<p>For example, giving a user the role of <code>Admin</code> may mean they would have been given<code>Advanced Create</code>, <code>Edit</code>, <code>Delete</code>, and <code>View</code> user privileges. Whereas, you may want to only give them <code>View</code> and <code>Basic Create</code> permissions.</p>
<p>Claims-based access control can allow for finer tuning of a specific user's permissions. The application can either check that the claim simply exists on a user, or whether a particular value is assigned to the claim.</p>
<p>As an example, a claim called <code>CreateUser</code> could be given to a user, and this is checked when creating a user. Or you could assign a value of <code>Advanced</code> to the same claim, and then have different actions and user interface available depending whether the value was <code>Advanced</code> or <code>Basic</code>.</p>
<h2 id="heading-whats-the-difference-between-authentication-and-authorization">What's the Difference between Authentication and Authorization?</h2>
<p>So now that we have a better understanding of the terms, let's look at a scenario you may be familiar with that involves both processes.</p>
<p>At a dinner party with an exclusive guest list, each guest is given a nickname and a secret password.</p>
<p>Upon arrival, a security guard asks you for your nickname and secret password. They then <strong>authenticate</strong> your credentials against the list they have. If your credentials match, you are handed an envelope showing you've been allowed in.</p>
<p>Once inside you are allowed to access the party and public areas of the venue as these require no <strong>authorization</strong> _(_everyone has the permission to enjoy the party). However, you then want to visit the VIP area.</p>
<p>As you approach, another security personnel asks to open your envelope (your permissions and roles). They take a look but unfortunately you do not have the VIP role, and therefore are not <strong>authorized</strong> to access.‌‌‌‌Put as simply as possible, authentication verifies the identity of a user or service allowing access, whereas authorization determines what they can do once they're in.</p>
<h2 id="heading-why-should-you-implement-both-authentication-and-authorization">Why Should You Implement Both Authentication and Authorization?</h2>
<p>As you can see, although authentication and authorization are very different, each plays an integral part in the security and integrity of the application or system.</p>
<p>These processes go hand in hand, and without one the other is kind of meaningless. If you can gain access to the Admin area, but do whatever you want once in there, it could lead to big problems.</p>
<p>On the other hand, you can't authorize individuals without knowing who they are! Which is why authentication always comes before authorization.</p>
<h2 id="heading-closing-thoughts">Closing Thoughts</h2>
<p>I hope this has been insightful and you now have a clearer understanding of the differences between Authorization and Authentication, and how to use them.</p>
<p>Remember:</p>
<ul>
<li>Authenticate =  Verifies the identity of a user or process.</li>
<li>Authorize = Determines if the user / system has permission to use a resource or carry out an action.</li>
</ul>
<p>Feel free to get in touch via Twitter if you wish to discuss this article in more detail <a target="_blank" href="http://twitter.com/gweaths">@gweaths</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Authenticate Users and Implement CORS in Node.js Apps ]]>
                </title>
                <description>
                    <![CDATA[ In this tutorial, you will learn how to authenticate users and secure endpoints in Node.js. You'll also see how to implement Cross-Origin Resource Sharing (CORS) in Node. So let's get started. Prerequisites You'll need the following to follow along w... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-authenticate-users-and-implement-cors-in-nodejs-applications/</link>
                <guid isPermaLink="false">66b905d1e8c4e204927a90ea</guid>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ authorization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ CORS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Idris Olubisi ]]>
                </dc:creator>
                <pubDate>Tue, 06 Jul 2021 16:02:13 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/06/Screenshot-2021-06-27-at-00.10.45.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this tutorial, you will learn how to authenticate users and secure endpoints in Node.js. You'll also see how to implement Cross-Origin Resource Sharing (CORS) in Node. So let's get started.</p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>You'll need the following to follow along with this tutorial: </p>
<ul>
<li>A working understanding of JavaScript.</li>
<li>A good understanding of Node.js.</li>
<li>A working knowledge of MongoDB or another database of your choice.</li>
<li><a target="_blank" href="https://www.postman.com/">Postman</a> and a basic understanding of how it works.</li>
</ul>
<p>Before we jump into the main part of the article, let's define some terms so we're all on the same page.</p>
<h2 id="heading-what-is-authentication">What is Authentication?</h2>
<p>Authentication and authorization may seem like the same thing. But there's a big difference between getting into a house (authentication) and what you can do once you're there (authorization).</p>
<p>Authentication is the process of confirming a user's identity by obtaining credentials and using those credentials to validate their identity. If the certificates are valid, the authorization procedure begins.</p>
<p>You are probably already familiar with the authentication process, because we all go through it daily – whether at work (logging onto your computer) or at home (passwords or logging into a website). In fact, most "things" connected to the Internet require you to provide credentials to prove your identity.</p>
<h2 id="heading-what-is-authorization">What is Authorization?</h2>
<p>Authorization is the process of granting authenticated users access to resources by verifying whether they have system access permissions or not. It also allows you to restrict access privileges by granting or denying specific licenses to authenticated users.</p>
<p>After the system authenticates your identity, authorization occurs, providing you full access to resources such as information, files, databases, finances, locations, and anything else. </p>
<p>This approval impacts your ability to access the system and the extent to which you can do so.</p>
<h2 id="heading-what-is-cross-origin-resource-sharing-cors">What is Cross-Origin Resource Sharing (CORS)?</h2>
<blockquote>
<p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS">CORS</a> is an HTTP header-based system that allows a server to specify any other origins (domain, scheme, or port) from which a browser should enable resources to be loaded other than its own. </p>
</blockquote>
<p>CORS also uses a system in which browsers send a "preflight" request to the server hosting the cross-origin help to ensure that it will allow the actual request.</p>
<p>We will be using the JSON web token standard to represent claims between two parties</p>
<h2 id="heading-what-are-json-web-tokens-jwt">What are JSON Web Tokens (JWT)?</h2>
<blockquote>
<p>JSON Web Tokens (JWT) are an open industry standard defined by RFC 7519 used to represent claims between two parties. <a target="_blank" href="https://jwt.io/introduction">jwt.io</a> </p>
</blockquote>
<p>You can use <a target="_blank" href="https://jwt.io">jwt.io</a> to decode, verify, and create JWTs, for example.</p>
<p>JWT defines a concise and self-contained way of exchanging information between two parties as a JSON object. You can review and trust this information because it is signed. </p>
<p>JWTs can be signed with a secret (using the HMAC algorithm) or a public/private key pair from RSA or ECDSA. We'll see some examples of how to use them in a bit.</p>
<p>Let's get started.</p>
<h2 id="heading-how-to-use-a-token-for-authentication-in-nodejs-development">How to Use a Token for Authentication in Node.js Development</h2>
<p>To get started, first we'll need to set up our project.</p>
<p>Navigate to a directory of your choice on your machine and open it in the terminal to launch Visual Studio Code.</p>
<p>Then execute:</p>
<pre><code class="lang-bash">code.
</code></pre>
<blockquote>
<p><strong>Note</strong>: If you don't have Visual Studio Code installed on your computer, <code>code .</code>  won't work. Just make sure you have it installed before trying this command.</p>
</blockquote>
<h3 id="heading-how-to-create-a-directory-and-set-it-up-with-npm">How to Create a Directory and Set it Up with <code>npm</code></h3>
<p>Create a directory and initialize <code>npm</code> by typing the following command:</p>
<ul>
<li>In Windows power shell:</li>
</ul>
<pre><code class="lang-bash">mkdir cors-auth-project

<span class="hljs-built_in">cd</span> cors-auth-project

npm init -y
</code></pre>
<ul>
<li>In Linux:</li>
</ul>
<pre><code class="lang-bash">mkdir cors-auth-project

<span class="hljs-built_in">cd</span> cors-auth-project

npm init -y
</code></pre>
<h3 id="heading-how-to-create-files-and-directories">How to Create Files and Directories</h3>
<p>In the previous step, we initialized npm with the command <code>npm init -y</code>, which automatically created a package.json file.</p>
<p>We will create the <code>model</code>, <code>middleware</code>, and <code>config</code> directories and their files, for example, <code>user.js</code>, <code>auth.js</code>, <code>database.js</code> using the commands below.</p>
<pre><code class="lang-bash">mkdir model middleware config

touch config/database.js middleware/auth.js model/user.js
</code></pre>
<p>We can now create the <code>index.js</code> and <code>app.js</code> files in the root directory of our project with this command:</p>
<pre><code class="lang-bash">touch app.js index.js
</code></pre>
<p>This will give us a folder structure like the one you see below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/Screenshot-2021-06-26-at-19.43.15.png" alt="folder structure" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-install-dependencies">How to Install Dependencies</h3>
<p>We'll install several dependencies like <code>mongoose</code>, <code>jsonwebtoken</code>, <code>express</code>, <code>dotenv</code>, <code>bcryptjs</code>, <code>cors</code> and development dependencies like <code>nodemon</code> to restart the server as we make changes automatically.</p>
<p>Because I'll be using MongoDB in this project, we'll install Mongoose, and the user credentials will be checked against what we have in our database. As a result, the entire authentication process isn't limited to the database we'll use in this tutorial.</p>
<pre><code class="lang-bash">npm install  cors mongoose express jsonwebtoken dotenv bcryptjs 

npm install nodemon -D
</code></pre>
<h3 id="heading-how-to-create-a-nodejs-server-and-connect-your-database">How to Create a Node.js Server and Connect your Database</h3>
<p>Now, add the following snippets to your <code>app.js</code>, <code>index.js</code>, <code>database.js</code>, and <code>.env</code> files in that order to establish our Node.js server and connect our database.</p>
<p>In our <code>database.js.</code>:</p>
<p><code>config/database.js</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">"mongoose"</span>);

<span class="hljs-keyword">const</span> { MONGO_URI } = process.env;

<span class="hljs-built_in">exports</span>.connect = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// Connecting to the database</span>
  mongoose
    .connect(MONGO_URI, {
      <span class="hljs-attr">useNewUrlParser</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">useUnifiedTopology</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">useCreateIndex</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">useFindAndModify</span>: <span class="hljs-literal">false</span>,
    })
    .then(<span class="hljs-function">() =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Successfully connected to database"</span>);
    })
    .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"database connection failed. exiting now..."</span>);
      <span class="hljs-built_in">console</span>.error(error);
      process.exit(<span class="hljs-number">1</span>);
    });
};
</code></pre>
<p>In our <code>app.js</code>:</p>
<p><code>auth-cors-project/app.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv"</span>).config();
<span class="hljs-built_in">require</span>(<span class="hljs-string">"./config/database"</span>).connect();
<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);

<span class="hljs-keyword">const</span> app = express();

app.use(express.json());

<span class="hljs-comment">// Logic goes here</span>

<span class="hljs-built_in">module</span>.exports = app;
</code></pre>
<p>In our <code>index.js</code>:</p>
<p><code>auth-cors-project/index.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">"http"</span>);
<span class="hljs-keyword">const</span> app = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./app"</span>);
<span class="hljs-keyword">const</span> server = http.createServer(app);

<span class="hljs-keyword">const</span> { API_PORT } = process.env;
<span class="hljs-keyword">const</span> port = process.env.PORT || API_PORT;

<span class="hljs-comment">// server listening </span>
server.listen(port, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server running on port <span class="hljs-subst">${port}</span>`</span>);
});
</code></pre>
<p>Our file, as you can see, requires various environment variables. If you haven't already, create a new <code>.env</code> file and add your variables before running the application.</p>
<p>In our <code>.env.</code>:</p>
<pre><code class="lang-javascript">API_PORT=<span class="hljs-number">4001</span>

MONGO_URI= <span class="hljs-comment">// Your database URI</span>
</code></pre>
<p>Edit the scripts object in our <code>package.json</code> to look like the one below to start our server.</p>
<pre><code class="lang-javascript"><span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"start"</span>: <span class="hljs-string">"node index.js"</span>,
    <span class="hljs-string">"dev"</span>: <span class="hljs-string">"nodemon index.js"</span>,
    <span class="hljs-string">"test"</span>: <span class="hljs-string">"echo \"Error: no test specified\" &amp;&amp; exit 1"</span>
  }
</code></pre>
<p>We successfully inserted the above snippet into the files <code>app.js</code>, <code>index.js</code>, and <code>database.js</code>. So, we started by creating our Node.js server in <code>index.js</code> and then imported the <code>app.js</code> file, which already had routes configured.</p>
<p>Then, in database.js, we used Mongoose to build a database connection.</p>
<p><code>npm run dev</code> is the command to start our application.</p>
<p>As long as they haven't crashed, both the server and the database should be up and running.</p>
<h3 id="heading-how-to-create-a-user-model-and-route">How to Create a User Model and Route</h3>
<p>After registering for the first time, we'll establish our schema for the user details. Then, when logging in, we'll check them against the remembered credentials.</p>
<p>In the model folder, add the following snippet to <code>user.js</code>:</p>
<p><code>model/user.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">"mongoose"</span>);

<span class="hljs-keyword">const</span> userSchema = <span class="hljs-keyword">new</span> mongoose.Schema({
  <span class="hljs-attr">first_name</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>, <span class="hljs-attr">default</span>: <span class="hljs-literal">null</span> },
  <span class="hljs-attr">last_name</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>, <span class="hljs-attr">default</span>: <span class="hljs-literal">null</span> },
  <span class="hljs-attr">email</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>, <span class="hljs-attr">unique</span>: <span class="hljs-literal">true</span> },
  <span class="hljs-attr">password</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span> },
  <span class="hljs-attr">token</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span> },
});

<span class="hljs-built_in">module</span>.exports = mongoose.model(<span class="hljs-string">"user"</span>, userSchema);
</code></pre>
<p>Now let's create the routes for <code>register</code> and <code>login</code>, respectively.</p>
<p>In <code>app.js</code> in the root directory, add the following snippet for the registration and login.</p>
<p><code>app.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// importing user context</span>
<span class="hljs-keyword">const</span> User = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./model/user"</span>);

<span class="hljs-comment">// Register</span>
app.post(<span class="hljs-string">"/register"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
<span class="hljs-comment">// our register logic goes here...</span>
});

<span class="hljs-comment">// Login</span>
app.post(<span class="hljs-string">"/login"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
<span class="hljs-comment">// our login logic goes here</span>
});
</code></pre>
<h3 id="heading-how-to-implement-register-and-login-functionality">How to Implement Register and Login Functionality</h3>
<p>We'll implement these two routes in our application. Before storing the credentials in our database, we'll use JWT to sign them and <code>bycrypt</code> to encrypt them.</p>
<p>We will: </p>
<ul>
<li>Get user input from the <code>/register</code> route.</li>
<li>Verify the user's input.</li>
<li>Check to see if the user has already been created.</li>
<li>Protect the user's password by encrypting it.</li>
<li>Make a user account in our database.</li>
<li>Finally, construct a JWT token that is signed.</li>
</ul>
<p>Modify the <code>/register</code> route structure we created earlier to look as shown below:</p>
<p><code>app.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// ...</span>

app.post(<span class="hljs-string">"/register"</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {

  <span class="hljs-comment">// Our register logic starts here</span>
   <span class="hljs-keyword">try</span> {
    <span class="hljs-comment">// Get user input</span>
    <span class="hljs-keyword">const</span> { firstName, lastName, email, password } = req.body;

    <span class="hljs-comment">// Validate user input</span>
    <span class="hljs-keyword">if</span> (!(email &amp;&amp; password &amp;&amp; firstName &amp;&amp; lastName)) {
      res.status(<span class="hljs-number">400</span>).send(<span class="hljs-string">"All input is required"</span>);
    }

    <span class="hljs-comment">// check if user already exist</span>
    <span class="hljs-comment">// Validate if user exist in our database</span>
    <span class="hljs-keyword">const</span> oldUser = <span class="hljs-keyword">await</span> User.findOne({ email });

    <span class="hljs-keyword">if</span> (oldUser) {
      <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">409</span>).send(<span class="hljs-string">"User Already Exist. Please Login"</span>);
    }

    <span class="hljs-comment">//Encrypt user password</span>
    encryptedUserPassword = <span class="hljs-keyword">await</span> bcrypt.hash(password, <span class="hljs-number">10</span>);

    <span class="hljs-comment">// Create user in our database</span>
    <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> User.create({
      <span class="hljs-attr">first_name</span>: firstName,
      <span class="hljs-attr">last_name</span>: lastName,
      <span class="hljs-attr">email</span>: email.toLowerCase(), <span class="hljs-comment">// sanitize</span>
      <span class="hljs-attr">password</span>: encryptedUserPassword,
    });

    <span class="hljs-comment">// Create token</span>
    <span class="hljs-keyword">const</span> token = jwt.sign(
      { <span class="hljs-attr">user_id</span>: user._id, email },
      process.env.TOKEN_KEY,
      {
        <span class="hljs-attr">expiresIn</span>: <span class="hljs-string">"5h"</span>,
      }
    );
    <span class="hljs-comment">// save user token</span>
    user.token = token;

    <span class="hljs-comment">// return new user</span>
    res.status(<span class="hljs-number">201</span>).json(user);
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-built_in">console</span>.log(err);
  }
  <span class="hljs-comment">// Our register logic ends here</span>
});

<span class="hljs-comment">// ...</span>
</code></pre>
<blockquote>
<p><strong>Note:</strong> Update your <code>.env</code> file with a <code>TOKEN_KEY</code>, which can be a random string.</p>
</blockquote>
<p>Using Postman to test the endpoint, we'll get the response shown below after successful registration.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/Screenshot-2021-06-26-at-22.57.16.png" alt="user registration" width="600" height="400" loading="lazy"></p>
<p>We will: </p>
<ul>
<li>Get user input for the <code>/login</code> route.</li>
<li>Verify the user's input.</li>
<li>Check to see if the user is genuine.</li>
<li>Compare the user's password to the one we saved earlier in our database.</li>
<li>Finally, construct a JWT token that is signed.</li>
</ul>
<p>Make the <code>/login</code> route structure that we defined earlier look like this:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// ...</span>

app.post(<span class="hljs-string">"/login"</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {

  <span class="hljs-comment">// Our login logic starts here</span>
   <span class="hljs-keyword">try</span> {
    <span class="hljs-comment">// Get user input</span>
    <span class="hljs-keyword">const</span> { email, password } = req.body;

    <span class="hljs-comment">// Validate user input</span>
    <span class="hljs-keyword">if</span> (!(email &amp;&amp; password)) {
      res.status(<span class="hljs-number">400</span>).send(<span class="hljs-string">"All input is required"</span>);
    }
    <span class="hljs-comment">// Validate if user exist in our database</span>
    <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> User.findOne({ email });

    <span class="hljs-keyword">if</span> (user &amp;&amp; (<span class="hljs-keyword">await</span> bcrypt.compare(password, user.password))) {
      <span class="hljs-comment">// Create token</span>
      <span class="hljs-keyword">const</span> token = jwt.sign(
        { <span class="hljs-attr">user_id</span>: user._id, email },
        process.env.TOKEN_KEY,
        {
          <span class="hljs-attr">expiresIn</span>: <span class="hljs-string">"5h"</span>,
        }
      );

      <span class="hljs-comment">// save user token</span>
      user.token = token;

      <span class="hljs-comment">// user</span>
      <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">200</span>).json(user);
    }
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).send(<span class="hljs-string">"Invalid Credentials"</span>);

  <span class="hljs-comment">// Our login logic ends here</span>
});

<span class="hljs-comment">// ...</span>
</code></pre>
<p>Using Postman to test, we'll get the response shown below after a successful login.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/Screenshot-2021-06-26-at-23.00.45.png" alt="user login" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-create-middleware-for-authentication">How to Create Middleware for Authentication</h3>
<p>We can now create and login a user successfully. Now, we'll establish a route that requires a user token in the header, which will be the JWT token we created before.</p>
<p>Add the following snippet inside <code>auth.js</code>:</p>
<p><code>middleware/auth.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> jwt = <span class="hljs-built_in">require</span>(<span class="hljs-string">"jsonwebtoken"</span>);

<span class="hljs-keyword">const</span> config = process.env;

<span class="hljs-keyword">const</span> verifyToken = <span class="hljs-function">(<span class="hljs-params">req, res, next</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> token =
    req.body.token || req.query.token || req.headers[<span class="hljs-string">"x-access-token"</span>];

  <span class="hljs-keyword">if</span> (!token) {
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">403</span>).send(<span class="hljs-string">"A token is required for authentication"</span>);
  }
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> decoded = jwt.verify(token, config.TOKEN_KEY);
    req.user = decoded;
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">401</span>).send(<span class="hljs-string">"Invalid Token"</span>);
  }
  <span class="hljs-keyword">return</span> next();
};

<span class="hljs-built_in">module</span>.exports = verifyToken;
</code></pre>
<p>To test the middleware, create the <code>/welcome</code> route and edit app.js with the following code:</p>
<p><code>app.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> auth = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./middleware/auth"</span>);

app.post(<span class="hljs-string">"/welcome"</span>, auth, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.status(<span class="hljs-number">200</span>).send(<span class="hljs-string">"Welcome to FreeCodeCamp 🙌"</span>);
});
</code></pre>
<p>When we try to access the /welcome route we just built without sending a token in the header with the x-access-token key, we get the following response:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/Screenshot-2021-06-26-at-23.09.13.png" alt="failed response" width="600" height="400" loading="lazy"></p>
<p>We can now re-test by adding a token in the header with the key x-access-token.</p>
<p>This is the response you'll get:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/success-response.png" alt="success response" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-implement-cross-origin-resource-sharing-cors">How to Implement Cross-Origin Resource Sharing (CORS)</h2>
<p><a target="_blank" href="https://www.npmjs.com/package/cors">CORS</a> is a Node.js package that provides a Connect/Express middleware that you can. use to enable CORS with a variety of parameters.</p>
<ol>
<li>It's easy to use (Enable All CORS Requests)</li>
</ol>
<p>Adding the following snippet to <code>app.js</code> allows us to add CORS to our application and enable all CORS requests.</p>
<pre><code><span class="hljs-comment">// ...</span>

<span class="hljs-keyword">const</span> cors = <span class="hljs-built_in">require</span>(<span class="hljs-string">"cors"</span>) <span class="hljs-comment">//Newly added</span>
<span class="hljs-keyword">const</span> app = express();

app.use(cors()) <span class="hljs-comment">// Newly added</span>


app.use(express.json({ <span class="hljs-attr">limit</span>: <span class="hljs-string">"50mb"</span> }));

<span class="hljs-comment">// ...</span>
</code></pre><ol start="2">
<li>You can enable CORS for a single route</li>
</ol>
<p>Using the <code>/welcome</code> route as an example, you can activate CORS for a single route in your application by adding the following snippet in <code>app.js.</code>:</p>
<pre><code>app.get(<span class="hljs-string">'/welcome'</span>, cors(), auth, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.status(<span class="hljs-number">200</span>).send(<span class="hljs-string">"Welcome to FreeCodeCamp 🙌 "</span>);
});
</code></pre><ol start="3">
<li>How to configure CORS</li>
</ol>
<p>We can set options in the CORS package by adding parameters to configure it, as shown below:</p>
<pre><code><span class="hljs-comment">// ...</span>

<span class="hljs-keyword">const</span> corsOptions = {
  <span class="hljs-attr">origin</span>: <span class="hljs-string">'http://example.com'</span>,
  <span class="hljs-attr">optionsSuccessStatus</span>: <span class="hljs-number">200</span> <span class="hljs-comment">// for some legacy browsers</span>
}

app.get(<span class="hljs-string">'/welcome'</span>, cors(corsOptions), auth, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.status(<span class="hljs-number">200</span>).send(<span class="hljs-string">"Welcome to FreeCodeCamp 🙌 "</span>);
});

<span class="hljs-comment">// ...</span>
</code></pre><p>You can check out <a target="_blank" href="https://www.npmjs.com/package/cors">NPM CORS PACKAGE</a> to read more about Cross-Origin Resource Sharing.</p>
<p>You can <a target="_blank" href="https://github.com/Olanetsoft/auth-cors-demo">click here</a> to check out the complete code on GitHub.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, we learned about JWT, authentication, authorization, and CORS. We also learned how to create an API in Node.js that uses a JWT token for authentication.</p>
<p>Thank you for reading!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ API Security – How to Authenticate and Authorise API’s in .NET 5 ]]>
                </title>
                <description>
                    <![CDATA[ By Arjav Dave In my 11 years as a developer, I have seen so many API's that have major security flaws. They either lack proper authentication or authorisation or both.  Developers might feel like everything's ok, since those endpoints are usually not... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/authenticate-and-authorize-apis-in-dotnet5/</link>
                <guid isPermaLink="false">66d84de029e30bc0ad47753a</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ authorization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ information security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 31 Mar 2021 21:22:23 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/03/mask.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Arjav Dave</p>
<p>In my 11 years as a developer, I have seen so many API's that have major security flaws. They either lack proper authentication or authorisation or both. </p>
<p>Developers might feel like everything's ok, since those endpoints are usually not public. But it is a huge security loop hole which anyone can easily target.</p>
<p>To better understand API security, let's create a demo project for the FBI. There will be an Admin who can enroll FBI Agents and change their clearance levels. </p>
<p>FBI Agents with <em>Clearance Level 1</em> will be able to access public files, and agents with <em>Clearance Level 2</em> will be able to access pubic and classified files.</p>
<p>But before we get started, here's some theory.</p>
<h2 id="heading-how-authentication-works">How Authentication Works</h2>
<p>Our Agent has successfully cleared all their exams; time to enroll them. In order to do that they will provide their documents and in return will get their badge.</p>
<p>In the above scenario, <em>providing documents</em> is like logging in – where once verified, the agent will be provided with a token (badge). This process is called <em>Authentication</em>. It determines whether agents are who they claim to be.</p>
<p>We are going to use JSON Web Tokens (JWT) Bearer tokens for authentication. <em>Bearer tokens</em> are a type of token that's generated by servers, and which contain details of the claims/roles of a user trying to login. Bearer tokens are mostly structured tokens like JWT. You can <a target="_blank" href="https://jwt.io/introduction">read more about JWT here</a> if you want to learn more.</p>
<h2 id="heading-how-authorisation-works">How Authorisation Works</h2>
<p>Now since the FBI Agent has gotten their badge, they can enter the FBI building. They are also able to access public files, but when trying to access classified files they get a <a target="_blank" href="https://www.freecodecamp.org/news/http-401-error-vs-http-403-error-status-code-responses-explained/">401 error</a>.</p>
<p>This is because FBI Agent is not <em>authorised</em> to access classified files. <em>Authorisation</em> determines what agents can and cannot access.</p>
<p>As mentioned above, the JWT Bearer token contains claims/roles. Based on it, our server decides whether to give access to a private resource or not.</p>
<h2 id="heading-access-flow">Access Flow</h2>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y1pcf6w2cjhtj9hgzm8v.jpg" alt="Access Flow" width="600" height="400" loading="lazy"></p>
<p>As you can see in the above diagram, on successful login the server returns a Bearer token. The client uses the bearer token in subsequent calls to access a private resource.</p>
<p>These are the two main concepts that we are going to implement in our article.</p>
<p>Enough with the theory, show me some code!</p>
<h2 id="heading-how-to-set-up-our-project">How to Set Up our Project</h2>
<p>Create a new project by executing the command <strong><code>dotnet new webapi --name FBI</code></strong> from your CLI. It will create a project with a sample WeatherForecast API.</p>
<p>Why work on WeatherForecast when we can work on FBI? Go ahead and delete the <code>WeatherForecast.cs</code> file.</p>
<p>Add the necessary dependencies by executing these commands:</p>
<pre><code>dotnet add package Microsoft.IdentityModel.Tokens --version <span class="hljs-number">6.9</span><span class="hljs-number">.0</span>
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer --version <span class="hljs-number">5.0</span><span class="hljs-number">.4</span>
</code></pre><p>In the <code>ConfigureServices</code> function in your <code>Startup.cs</code> file, add the below code:</p>
<pre><code><span class="hljs-keyword">var</span> TokenValidationParameters = <span class="hljs-keyword">new</span> TokenValidationParameters
{
    ValidIssuer = <span class="hljs-string">"https://fbi-demo.com"</span>,
    ValidAudience = <span class="hljs-string">"https://fbi-demo.com"</span>,
    IssuerSigningKey = <span class="hljs-keyword">new</span> SymmetricSecurityKey(Encoding.UTF8.GetBytes(<span class="hljs-string">"SXkSqsKyNUyvGbnHs7ke2NCq8zQzNLW7mPmHbnZZ"</span>)),
    ClockSkew = TimeSpan.Zero <span class="hljs-comment">// remove delay of token when expire</span>
};
</code></pre><p>We are defining the parameters for validating a token. Make sure that the length of the string for generating <code>SymmetricSecurityKey</code> is 32.</p>
<p>Next, setup the services to add authentication for API's like this:</p>
<pre><code>services
    .AddAuthentication(<span class="hljs-function"><span class="hljs-params">options</span> =&gt;</span>
    {
        options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
    })
    .AddJwtBearer(<span class="hljs-function"><span class="hljs-params">cfg</span> =&gt;</span>
    {
        cfg.TokenValidationParameters = TokenValidationParameters;
    });
</code></pre><p>The <code>AddAuthentication</code> method registers services required by authentication services. It also configures the JWT Bearer Authentication as the default scheme.</p>
<p>The <code>AddJwtBearer</code> enables JWT-bearer authentication and setting the <code>TokenValidationParameters</code> defined above.</p>
<p>Now let's add some Authorisation claims for our <code>Agent</code> and <code>Admin</code>.</p>
<pre><code>services.AddAuthorization(<span class="hljs-function"><span class="hljs-params">cfg</span> =&gt;</span>
    {
        cfg.AddPolicy(<span class="hljs-string">"Admin"</span>, <span class="hljs-function"><span class="hljs-params">policy</span> =&gt;</span> policy.RequireClaim(<span class="hljs-string">"type"</span>, <span class="hljs-string">"Admin"</span>));
        cfg.AddPolicy(<span class="hljs-string">"Agent"</span>, <span class="hljs-function"><span class="hljs-params">policy</span> =&gt;</span> policy.RequireClaim(<span class="hljs-string">"type"</span>, <span class="hljs-string">"Agent"</span>));
        cfg.AddPolicy(<span class="hljs-string">"ClearanceLevel1"</span>, <span class="hljs-function"><span class="hljs-params">policy</span> =&gt;</span> policy.RequireClaim(<span class="hljs-string">"ClearanceLevel"</span>, <span class="hljs-string">"1"</span>, <span class="hljs-string">"2"</span>));
        cfg.AddPolicy(<span class="hljs-string">"ClearanceLevel2"</span>, <span class="hljs-function"><span class="hljs-params">policy</span> =&gt;</span> policy.RequireClaim(<span class="hljs-string">"ClearanceLevel"</span>, <span class="hljs-string">"2"</span>));
    });
</code></pre><p>The <code>AddAuthorization</code> method registers services required for authorisation. We are also adding claims for <code>Admin</code>, <code>Agent</code>, <code>ClearanceLevel1</code> and <code>ClearanceLevel2</code> by calling <code>AddPolicy</code>. </p>
<p>A claim is a name value pair that represents what the subject is. Since clearance level 2 can also access clearance level 1, we have put <em>"1", "2"</em> in ClearanceLevel1. You can read more about claims <em><a target="_blank" href="https://docs.microsoft.com/en-us/aspnet/core/security/authorization/claims?view=aspnetcore-5.0">here</a></em>.</p>
<p>Lastly, in the <code>Configure</code> method, add the below line just above <code>app.UseAuthorization();</code>:</p>
<pre><code>app.UseAuthentication();
</code></pre><h2 id="heading-the-admin-controller-file">The Admin Controller File</h2>
<p>Rename your file <code>WeatherForecastController.cs</code> to <code>AdminController.cs</code>. Do change the class name and constructor names as well. Finally, remove everything except the constructor.</p>
<pre><code>using Microsoft.AspNetCore.Mvc;

namespace FBI.Controllers
{
    [ApiController]
    [Route(<span class="hljs-string">"[controller]"</span>)]
    public <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AdminController</span> : <span class="hljs-title">ControllerBase</span>
    </span>{
        public AdminController() { }
    }
}
</code></pre><h3 id="heading-how-to-set-up-the-login-api">How to Set Up the Login API</h3>
<p>Let's create a login API for <code>Admin</code> so that they can get a token to perform other tasks.</p>
<pre><code>[HttpPost]
[Route(<span class="hljs-string">"[action]"</span>)]
public IActionResult Login([FromBody] User User)
{
    <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> Authenticate Admin with Database</span>
    <span class="hljs-comment">// If not authenticate return 401 Unauthorized</span>
    <span class="hljs-comment">// Else continue with below flow</span>

    <span class="hljs-keyword">var</span> Claims = <span class="hljs-keyword">new</span> List&lt;Claim&gt;
            {
                <span class="hljs-keyword">new</span> Claim(<span class="hljs-string">"type"</span>, <span class="hljs-string">"Admin"</span>),
            };

    <span class="hljs-keyword">var</span> Key = <span class="hljs-keyword">new</span> SymmetricSecurityKey(Encoding.UTF8.GetBytes(<span class="hljs-string">"SXkSqsKyNUyvGbnHs7ke2NCq8zQzNLW7mPmHbnZZ"</span>));

    <span class="hljs-keyword">var</span> Token = <span class="hljs-keyword">new</span> JwtSecurityToken(
        <span class="hljs-string">"https://fbi-demo.com"</span>,
        <span class="hljs-string">"https://fbi-demo.com"</span>,
        Claims,
        <span class="hljs-attr">expires</span>: DateTime.Now.AddDays(<span class="hljs-number">30.0</span>),
        <span class="hljs-attr">signingCredentials</span>: <span class="hljs-keyword">new</span> SigningCredentials(Key, SecurityAlgorithms.HmacSha256)
    );

    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> OkObjectResult(<span class="hljs-keyword">new</span> JwtSecurityTokenHandler().WriteToken(Token));
}
</code></pre><p>In the above code, <code>User</code> is a model with properties <code>Username</code> and <code>Password</code>. We are also creating an object of <code>JwtSecurityToken</code> using configurations that we have used in our <code>Startup.cs</code> file. The token is then converted to a string and returned in an <code>OkObjectResult</code>.</p>
<p>You can now open Swagger and execute the API to see a bearer token. A bearer token will be returned as you can see below.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aedozuzics30gunpp3b5.png" alt="Bearer Token Response" width="600" height="400" loading="lazy"></p>
<p>Keep the token handy since we are going to use it in the next section. You can also visit <a target="_blank" href="https://jwt.io">https://jwt.io</a> to analyse your token.</p>
<h3 id="heading-how-to-generate-the-badge-api">How to Generate the Badge API</h3>
<p>Generating the badge for an <code>Agent</code> is a sensitive task and should only be authorised by an <code>Admin</code>. We are going to add an <code>Authorize</code> attribute for the <code>GenerateBadge</code> API.</p>
<pre><code>[HttpPost]
[Route(<span class="hljs-string">"[action]"</span>)]
[Authorize(Policy = <span class="hljs-string">"Admin"</span>)]
public IActionResult GenerateBadge([FromBody] Agent Agent)
{
    <span class="hljs-keyword">var</span> Claims = <span class="hljs-keyword">new</span> List&lt;Claim&gt;
    {
        <span class="hljs-keyword">new</span> Claim(<span class="hljs-string">"type"</span>, <span class="hljs-string">"Agent"</span>),
        <span class="hljs-keyword">new</span> Claim(<span class="hljs-string">"ClearanceLevel"</span>, Agent.ClearanceLevel.ToString()),
    };

    <span class="hljs-keyword">var</span> Key = <span class="hljs-keyword">new</span> SymmetricSecurityKey(Encoding.UTF8.GetBytes(<span class="hljs-string">"SXkSqsKyNUyvGbnHs7ke2NCq8zQzNLW7mPmHbnZZ"</span>));

    <span class="hljs-keyword">var</span> Token = <span class="hljs-keyword">new</span> JwtSecurityToken(
        <span class="hljs-string">"https://fbi-demo.com"</span>,
        <span class="hljs-string">"https://fbi-demo.com"</span>,
        Claims,
        <span class="hljs-attr">expires</span>: DateTime.Now.AddDays(<span class="hljs-number">30.0</span>),
        <span class="hljs-attr">signingCredentials</span>: <span class="hljs-keyword">new</span> SigningCredentials(Key, SecurityAlgorithms.HmacSha256)
    );

    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> OkObjectResult(<span class="hljs-keyword">new</span> JwtSecurityTokenHandler().WriteToken(Token));
}
</code></pre><p>Here, <code>Agent</code> is a model with properties <code>Name</code> as string and <code>ClearanceLevel</code> as int.</p>
<p>Now when you go back to swagger and try to execute the <code>GenerateBadge</code> API it will give you a 401 Unauthorised response. We are getting this error because we have not passed the bearer token.</p>
<p>To be able to add the Authorize header in Swagger, change the <code>services.AddSwaggerGen</code> as below:</p>
<pre><code>services.AddSwaggerGen(<span class="hljs-function"><span class="hljs-params">c</span> =&gt;</span>
{
    c.SwaggerDoc(<span class="hljs-string">"v1"</span>, <span class="hljs-keyword">new</span> OpenApiInfo { Title = <span class="hljs-string">"FBI"</span>, Version = <span class="hljs-string">"v1"</span> });
    c.AddSecurityDefinition(<span class="hljs-string">"Bearer"</span>, <span class="hljs-keyword">new</span> OpenApiSecurityScheme
    {
        In = ParameterLocation.Header,
        Description = <span class="hljs-string">"Please enter JWT with Bearer into field"</span>,
        Name = <span class="hljs-string">"Authorization"</span>,
        Type = SecuritySchemeType.ApiKey
    });
    c.AddSecurityRequirement(<span class="hljs-keyword">new</span> OpenApiSecurityRequirement {
    { <span class="hljs-keyword">new</span> OpenApiSecurityScheme
            {
                Reference = <span class="hljs-keyword">new</span> OpenApiReference { Type = ReferenceType.SecurityScheme, Id = <span class="hljs-string">"Bearer"</span>}
            },
        <span class="hljs-keyword">new</span> string[] {}
    }
    });
});
</code></pre><p>When you refresh Swagger in your browser you will notice an <em>Authorize</em> button on the right side above the list of APIs.</p>
<p>Click on the newly added Authorize button in Swagger which will open up a dialog. We need to mention what type of token it is. So first enter <em>Bearer</em> in the field then a space and then the token generated from the <em>/Admin/Login</em> API from the previous section.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5ks0jtoy39ogcpa61s71.png" alt="Authorization Header" width="600" height="400" loading="lazy"></p>
<p>Click on the header to lock in the token. Now you are all set. When you execute the <code>GenerateBadge</code> API again you will get a token (analogous to badge). Keep this token handy, since we require it in the next section. Also make sure to <strong>pass ClearanceLevel as 1</strong> for now.</p>
<h2 id="heading-how-to-set-up-the-agent-controller">How to Set Up the Agent Controller</h2>
<p>Create a new file called <code>AgentController.cs</code> with the below content:</p>
<pre><code>using Microsoft.AspNetCore.Mvc;

namespace FBI.Controllers
{
    [ApiController]
    [Route(<span class="hljs-string">"[controller]"</span>)]
    [Authorize(Policy = <span class="hljs-string">"Agent"</span>)]
    public <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AgentController</span> : <span class="hljs-title">ControllerBase</span>
    </span>{
        public AgentController() { }
    }
}
</code></pre><p>As you can see above, we are authorising the whole controller for Agent's access only. So even Admin won't be able to access the API's we are going to create.</p>
<h3 id="heading-how-to-access-the-records-apis">How to Access the Record's APIs</h3>
<p>Let's add the APIs to access both public and classified files.</p>
<pre><code>[HttpGet]
[Route(<span class="hljs-string">"[action]"</span>)]
[Authorize(Policy = <span class="hljs-string">"ClearanceLevel1"</span>)]
public ActionResult&lt;<span class="hljs-built_in">String</span>&gt; AccessPublicFiles()
{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> OkObjectResult(<span class="hljs-string">"Public Files Accessed"</span>);
}

[HttpGet]
[Route(<span class="hljs-string">"[action]"</span>)]
[Authorize(Policy = <span class="hljs-string">"ClearanceLevel2"</span>)]
public ActionResult&lt;<span class="hljs-built_in">String</span>&gt; AccessClassifiedFiles()
{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> OkObjectResult(<span class="hljs-string">"Classified Files Accessed"</span>);
}
</code></pre><p>We have added the <code>Authorize</code> attribute's for both API's such that public files can be accessed by <code>ClearanceLevel1</code> and classified files can be accessed by <code>ClearanceLevel2</code>.</p>
<p>If you try to access these API's with the Admin token you will get 403 Forbidden error. So go ahead and click on the <em>Authorize</em> button again and click on <em>logout</em>. Then, get the token from the above step and paste in the field with <em>Bearer</em> as a prefix<em>.</em></p>
<p>Now when you access the <em>/Agent/AccessPublicFiles</em> API you will see response 200 with the message <em>Public Files Accessed</em>. But when you try the classified API you get the 403 Forbidden error.</p>
<h2 id="heading-how-to-change-the-clearance-level">How to Change the Clearance Level</h2>
<p>Fast forward 3 years and our <em>Agent's</em> performance has been mind bogglingly good. Management has now decided to promote them to ClearanceLevel2.</p>
<p>The <em>Agent</em> goes to the <em>Admin</em> and asks them to provide a token/badge with Clearance Level 2.</p>
<p>The <em>Admin</em> calls the <em>/Admin/Login</em> API to generate their own token first. They then enter it in the <em>Authorize</em> dialog.</p>
<p>The admin then calls the <em>/Admin/GenerageBadge</em> API with value 2 in the ClearanceLevel. This generates a new token/badge which they then hand over to <em>Agent</em>.</p>
<p>The <em>Agent</em> enters this token/badge in the <em>Authorize</em> dialog and when they now call <em>/Agent/AccessClassifiedFiles</em> they are pleased to see the result <em>Classified Files Accessed</em>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>You can find the whole project <a target="_blank" href="https://github.com/shenanigan/fbi-demo">here</a> on GitHub.</p>
<p>API security is extremely important and shouldn't be taken lightly, even if it's for internal use only. Setup Authentication and Authorisation and you are halfway there.</p>
<p>There are other other security measures you can take against DDoS attacks, accepting API's from a particular IP or domain only, and so on.</p>
<p>How did you like the article? What other security measures do you usually take? Any feedbacks or comments?</p>
<p>You can checkout out more tutorials on <a target="_blank" href="https://daveops.co.in">my site</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Set Up Java Spring Boot JWT Authorization and Authentication ]]>
                </title>
                <description>
                    <![CDATA[ By Yiğit Kemal Erinç In the past month, I had a chance to implement JWT auth for a side project. I have previously worked with JWT in Ruby on Rails, but this was my first time in Spring.  In this post, I will try to explain what I have ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-setup-jwt-authorization-and-authentication-in-spring/</link>
                <guid isPermaLink="false">66d45e44182810487e0ce155</guid>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ authorization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JSON Web Tokens ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JWT ]]>
                    </category>
                
                    <category>
                        <![CDATA[ spring-boot ]]>
                    </category>
                
                    <category>
                        <![CDATA[ spring security ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 12 Aug 2020 20:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/08/jwt.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Yiğit Kemal Erinç</p>
<p>In the past month, I had a chance to implement JWT auth for a side project. I have previously worked with JWT in Ruby on Rails, but this was my first time in Spring. </p>
<p>In this post, I will try to explain what I have learned and applied in my project to share my experience and hopefully help some people. </p>
<p>We will start by taking a quick look at the theory behind JWT and how it works. Then we will look at how to implement it in a Spring Boot application.</p>
<h2 id="heading-jwt-basics">JWT Basics</h2>
<p>JWT, or JSON Web Tokens (<a target="_blank" href="https://tools.ietf.org/html/rfc7519">RFC 7519</a>), is a standard that is mostly used for securing REST APIs. Despite being a relatively new technology, it is gaining rapid popularity.</p>
<p>In the JWT auth process, the front end (client) firstly sends some credentials to authenticate itself (username and password in our case, since we're working on a web application). </p>
<p>The server (the Spring app in our case) then checks those credentials, and if they are valid, it generates a JWT and returns it. </p>
<p>After this step client has to provide this token in the request’s <strong>Authorization</strong> header in the “Bearer TOKEN” form. The back end will check the validity of this token and authorize or reject requests. The token may also store user roles and authorize the requests based on the given authorities.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/1.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-implementation">Implementation</h2>
<p>Now let’s see how we can implement the JWT login and save mechanism in a real Spring application.</p>
<h3 id="heading-dependencies">Dependencies</h3>
<p>You can see the list of Maven dependencies that our example code uses below. Note that the core dependencies like Spring Boot and Hibernate are not included in this screenshot.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/2-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-saving-users">Saving Users</h3>
<p>We will start by creating controllers to save users securely and authenticate them based on username and password.</p>
<p>We have a model entity called User. It is a simple entity class that maps to the <strong>USER</strong> table. You can use whatever properties you need depending on your application.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/3-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We also have a simple <strong>UserRepository</strong> class to save users. We need to override the <strong>findByUsername</strong> method since we will use it in authentication.</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">UserRepository</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">JpaRepository</span>&lt;<span class="hljs-title">User</span>, <span class="hljs-title">String</span>&gt;</span>{ 
    <span class="hljs-function">User <span class="hljs-title">findByUsername</span><span class="hljs-params">(String username)</span></span>; 
}
</code></pre>
<p>We should never store plaintext passwords in the database because many users tend to use the same password for multiple sites. </p>
<p>There are many different hashing algorithms, but the most commonly used one is <strong>BCrypt</strong> and it is a recommended method of secure hashing. You can check out <a target="_blank" href="https://security.blogoverflow.com/2013/09/about-secure-password-hashing/#:~:text=Passwords%20should%20be%20hashed%20with,providing%20most%20security%20is%20bcrypt.">this</a> article for more information on the topic.</p>
<p>To hash the password, we will define a <strong>BCrypt</strong> bean in <strong>@SpringBootApplication</strong> and annotate the main class as follows:</p>
<pre><code class="lang-java"><span class="hljs-meta">@Bean</span> <span class="hljs-function"><span class="hljs-keyword">public</span> BCryptPasswordEncoder <span class="hljs-title">bCryptPasswordEncoder</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> BCryptPasswordEncoder(); 
}
</code></pre>
<p>We will call the methods on this bean when we need to hash a password.</p>
<p>We also need a UserController to save users. We create the controller, annotate it with <strong>@RestController,</strong> and define the corresponding mapping. </p>
<p>In our application, we save the user based on a DTO object that is passed from the front end. You can also pass a User object in <strong>@RequestBody</strong>.</p>
<p>After we pass the DTO object, we encrypt the password field using the <strong>BCrypt</strong> bean we created earlier. You could also do this in the controller, but it is a better practice to put this logic in the service class.</p>
<pre><code class="lang-java"><span class="hljs-meta">@Transactional(rollbackFor = Exception.class)</span> 
<span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">saveDto</span><span class="hljs-params">(UserDto userDto)</span> </span>{ 
    userDto.setPassword(bCryptPasswordEncoder
           .encode(userDto.getPassword())); 
    <span class="hljs-keyword">return</span> save(<span class="hljs-keyword">new</span> User(userDto)).getId(); 
}
</code></pre>
<h3 id="heading-authentication-filter">Authentication Filter</h3>
<p>We need authentication to make sure that the user is really who they claim to be. We will be using the classic username/password pair to accomplish this.</p>
<p>Here are the steps to implement authentication:</p>
<ol>
<li>Create our Authentication Filter that extends <strong>UsernamePasswordAuthenticationFilter</strong></li>
<li>Create a security configuration class that extends <strong>WebSecurityConfigurerAdapter</strong> and apply the filter</li>
</ol>
<p>Here is the code for our Authentication Filter – as you might know, filters are the backbone of Spring Security.</p>


<p>Let’s go over this code step by step.</p>
<p>This class extends <strong>UsernamePasswordAuthenticationFilter</strong> which is the default class for password authentication in Spring Security. We extend it to define our custom authentication logic.</p>
<p>We make a call to the <strong>setFilterProcessesUrl</strong> method in our constructor. This method sets the default login URL to the provided parameter. </p>
<p>If you remove this line, Spring Security creates the <strong>“/login”</strong> endpoint by default. It defines the login endpoint for us, which is why we will not define a login endpoint in our controller explicitly. </p>
<p>After this line our login endpoint will be <strong>/api/services/controller/user/login</strong>. You can use this function to stay consistent with your endpoints.</p>
<p>We override the <strong>attemptAuthentication</strong> and <strong>successfulAuthentication</strong> methods of the <strong>UsernameAuthenticationFilter</strong> class.</p>
<p>The <strong>attemptAuthentication</strong> function runs when the user tries to log in to our application. It reads the credentials, creates a user POJO from them, and then checks the credentials to authenticate. </p>
<p>We pass the username, password, and an empty list. The empty list represents the authorities (roles), and we leave it as is since we do not have any roles in our application yet.</p>
<p>If the authentication is successful, the <strong>successfulAuthentication</strong> method runs. The parameters of this method are passed by Spring Security behind the scenes. </p>
<p>The <strong>attemptAuthentication</strong> method returns an <strong>Authentication</strong> object that contains the authorities we passed while attempting. </p>
<p>We want to return a token to user after authentication is successful, so we create the token using username, secret, and expiration date. We need to define the <strong>SECRET</strong> and <strong>EXPIRATION_DATE</strong> now.</p>


<p>We create a class to be a container for our constants. You can set the secret to whatever you want, but the best practice is making the secret key as long as your hash. We use the <strong>HS256</strong> algorithm in this example, so our secret key is 256 bits/32 chars.</p>
<p>The expiration time is set to 15 minutes, because it is the best practice against secret key brute-forcing attacks. The time is in milliseconds.</p>
<p>We have prepared our Authentication filter, but it is not active yet. We also need an Authorization filter, and then we will apply them both through a configuration class. </p>
<p>This filter will check the existence and validity of the access token on the Authorization header. We will specify which endpoints will be subject to this filter in our configuration class.</p>
<h3 id="heading-authorization-filter">Authorization Filter</h3>


<p>The <strong>doFilterInternal</strong> method intercepts the requests then checks the Authorization header. If the header is not present or doesn’t start with “BEARER”, it proceeds to the filter chain. </p>
<p>If the header is present, the <strong>getAuthentication</strong> method is invoked. <strong>getAuthentication</strong> verifies the JWT, and if the token is valid, it returns an access token which Spring will use internally. </p>
<p>This new token is then saved to SecurityContext. You can also pass in Authorities to this token if you need for role-based authorization.</p>
<p>Our filters are ready, and now we need to put them into action with the help of a configuration class.</p>
<h3 id="heading-configuration">Configuration</h3>


<p>We annotate this class with <strong>@EnableWebSecurity</strong> and extend <strong>WebSecurityConfigureAdapter</strong> to implement our custom security logic. </p>
<p>We autowire the BCrypt bean that we defined earlier. We also autowire the <strong>UserDetailsService</strong> to find the user’s account. </p>
<p>The most important method is the one which accepts an <strong>HttpSecurity</strong> object. Here we specify the secure endpoints and filters that we want to apply. We configure CORS, and then we permit all post requests to our sign up URL that we defined in the constants class. </p>
<p>You can add other ant matchers to filter based on URL patterns and roles, and you can <a target="_blank" href="https://stackoverflow.com/questions/44067650/spring-security-role-based-access">check</a> this StackOverflow question for examples regarding that. The other method configures the <strong>AuthenticationManager</strong> to use our encoder object as its password encoder while checking the credentials.</p>
<h3 id="heading-testing">Testing</h3>
<p>Let’s send a few requests to test if it works properly.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/4.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Here we send a GET request to access a protected resource. Our server responds with a 403 code. This is the expected behavior because we haven’t provided a token in the header. Now let’s create a user:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/5.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>To create a user, we send a post request with our User DTO data. We will use this user to login and get an access token.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/6.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Great! We got the token. After this point, we will use this token to access protected resources.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/7.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We provide the token in the Authorization header and we are now allowed access to our protected endpoint.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial I have walked you through the steps I took when implementing JWT authorization and password authentication in Spring. We also learned how to save a user securely. </p>
<p>Thank you for reading – I hope it was helpful to you. If you are interested in reading more content like this, feel free to subscribe to my blog at <a target="_blank" href="https://erinc.io">https://erinc.io</a>. :)</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
