<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Guillermo Olcina Martínez</title>
    <description>The latest articles on Forem by Guillermo Olcina Martínez (@guiolmar).</description>
    <link>https://forem.com/guiolmar</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3257712%2F163652a6-7cb1-4218-91c6-f56424bb68d4.jpeg</url>
      <title>Forem: Guillermo Olcina Martínez</title>
      <link>https://forem.com/guiolmar</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/guiolmar"/>
    <language>en</language>
    <item>
      <title>How to Protect Your FastAPI Public API with API Keys</title>
      <dc:creator>Guillermo Olcina Martínez</dc:creator>
      <pubDate>Tue, 05 Aug 2025 10:32:34 +0000</pubDate>
      <link>https://forem.com/guiolmar/how-to-protect-your-fastapi-public-api-with-api-keys-3c7c</link>
      <guid>https://forem.com/guiolmar/how-to-protect-your-fastapi-public-api-with-api-keys-3c7c</guid>
      <description>&lt;p&gt;FastAPI is a powerful web framework for building APIs quickly and efficiently in Python. But once your API is public, you’ll want to protect it from abuse. One simple and effective way is using &lt;strong&gt;API Keys&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this post, I’ll show you how to set up basic API Key validation in FastAPI.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔐 Why API Keys?
&lt;/h2&gt;

&lt;p&gt;API Keys let you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Identify the client making requests&lt;/li&gt;
&lt;li&gt;Limit usage (rate limiting, quota)&lt;/li&gt;
&lt;li&gt;Disable keys without affecting others&lt;/li&gt;
&lt;li&gt;Secure endpoints behind access controls&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🛠️ Step 1: Define Your API Key Dependency
&lt;/h2&gt;

&lt;p&gt;We'll use FastAPI's dependency injection system to require API keys on specific routes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HTTPException&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;API_KEYS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;123456&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;abcdef&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;my-secret-key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="c1"&gt;# Normally load this from a database or environment
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;verify_api_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x_api_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;(...)):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x_api_key&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;API_KEYS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;HTTPException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTP_401_UNAUTHORIZED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid or missing API Key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/public&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;public_endpoint&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;This is public&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/protected&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dependencies&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;verify_api_key&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;protected_endpoint&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You have access with a valid API key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧪 Testing
&lt;/h2&gt;

&lt;p&gt;You can test it with &lt;code&gt;curl&lt;/code&gt; or Postman:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:8000/protected &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"x-api-key: 123456"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the key is valid, you’ll get access. Otherwise, a 401 Unauthorized response.&lt;/p&gt;




&lt;h2&gt;
  
  
  📦 Optional: Use Limitly to Manage Keys, Limits &amp;amp; Plans
&lt;/h2&gt;

&lt;p&gt;If you're building a commercial API and want to manage API keys, track usage, and set limits without building it from scratch — check out &lt;a href="https://app.limitly.dev/" rel="noopener noreferrer"&gt;Limitly&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It’s a plug-and-play API access manager that works great with FastAPI.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;This approach is simple and scalable for small to medium APIs. For more advanced use cases, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Store keys in a database&lt;/li&gt;
&lt;li&gt;Add rate-limiting&lt;/li&gt;
&lt;li&gt;Track usage per key&lt;/li&gt;
&lt;li&gt;Disable compromised keys dynamically&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Protect your API early — it’s better than handling abuse later.&lt;/p&gt;

&lt;p&gt;Happy coding! 🧑‍💻&lt;/p&gt;

</description>
      <category>fastapi</category>
      <category>python</category>
      <category>backend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Secure Your Public API in Next.js Using API Keys</title>
      <dc:creator>Guillermo Olcina Martínez</dc:creator>
      <pubDate>Tue, 05 Aug 2025 10:30:44 +0000</pubDate>
      <link>https://forem.com/guiolmar/how-to-secure-your-public-api-in-nextjs-using-api-keys-356m</link>
      <guid>https://forem.com/guiolmar/how-to-secure-your-public-api-in-nextjs-using-api-keys-356m</guid>
      <description>&lt;p&gt;Exposing API routes publicly in your Next.js app can be dangerous if you don't protect them properly. If you're building something like a public-facing SaaS, internal tools, or microservices, validating API keys is a simple and effective way to protect your endpoints.&lt;/p&gt;

&lt;p&gt;In this post, you'll learn how to secure your &lt;code&gt;/api&lt;/code&gt; routes using API keys with minimal code.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔐 Step 1: Generate and store your API keys
&lt;/h2&gt;

&lt;p&gt;In a real-world scenario, you'd generate an API key for each client/user and store it securely in your database. But for the purpose of this example, we'll hardcode a key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/validateApiKey.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isValidApiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validKeys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;INTERNAL_API_KEY&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;validKeys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't forget to set your &lt;code&gt;INTERNAL_API_KEY&lt;/code&gt; in &lt;code&gt;.env.local&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INTERNAL_API_KEY=your-secret-key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧩 Step 2: Add middleware to protect routes
&lt;/h2&gt;

&lt;p&gt;Next.js supports &lt;a href="https://nextjs.org/docs/app/building-your-application/routing/middleware" rel="noopener noreferrer"&gt;Edge Middleware&lt;/a&gt; and route handlers. For this guide, we'll use a simple pattern in an API route:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// pages/api/secure.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextApiRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NextApiResponse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;isValidApiKey&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/lib/validateApiKey&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextApiRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextApiResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;apiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x-api-key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isValidApiKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unauthorized&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Access granted 🎉&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now test it using curl or Postman:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"x-api-key: your-secret-key"&lt;/span&gt; http://localhost:3000/api/secure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ✅ Best Practices
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use a proper database to store keys, and hash them if possible.&lt;/li&gt;
&lt;li&gt;Rotate and expire keys.&lt;/li&gt;
&lt;li&gt;Assign scopes or permissions to different API keys.&lt;/li&gt;
&lt;li&gt;Monitor usage and rate limit requests per key.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🛠️ Looking for a managed solution?
&lt;/h2&gt;

&lt;p&gt;If you're building a SaaS or API-first product and don't want to handle all of this manually, check out &lt;a href="https://app.limitly.dev" rel="noopener noreferrer"&gt;Limitly&lt;/a&gt;. It helps you manage API keys, enforce rate limits, and track usage — all via a simple SDK.&lt;/p&gt;




&lt;p&gt;Happy building! 🚀&lt;/p&gt;

</description>
      <category>api</category>
      <category>webdev</category>
      <category>nextjs</category>
      <category>programming</category>
    </item>
    <item>
      <title>🔐 How to Protect Your Public Express API Using API Keys</title>
      <dc:creator>Guillermo Olcina Martínez</dc:creator>
      <pubDate>Tue, 05 Aug 2025 10:26:52 +0000</pubDate>
      <link>https://forem.com/guiolmar/how-to-protect-your-public-express-api-using-api-keys-11e8</link>
      <guid>https://forem.com/guiolmar/how-to-protect-your-public-express-api-using-api-keys-11e8</guid>
      <description>&lt;p&gt;If you're building an API in Express.js and plan to expose it publicly — maybe to clients, third-party devs, or internal tools — you &lt;em&gt;need&lt;/em&gt; some way to control access.&lt;/p&gt;

&lt;p&gt;One of the most common and effective ways to do this is using &lt;strong&gt;API keys&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this post, I’ll walk you through a simple way to implement API key protection in your Express API. No fancy gateways, no unnecessary bloat — just straightforward logic you can build on.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚧 Why API Keys?
&lt;/h2&gt;

&lt;p&gt;API keys are unique tokens (usually strings) that your users include in their requests. You can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Identify who's calling your API.&lt;/li&gt;
&lt;li&gt;Set limits (like 1,000 requests per day).&lt;/li&gt;
&lt;li&gt;Revoke keys if needed.&lt;/li&gt;
&lt;li&gt;Analyze usage by key/project/client.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Perfect for public or semi-public APIs that don’t need full OAuth complexity.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Basic API Key Middleware in Express
&lt;/h2&gt;

&lt;p&gt;Here’s a minimal implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// middleware/apiKey.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validApiKeys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;abc123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// In real use, store these in a DB&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;def456&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;apiKeyMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;apiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x-api-key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;apiKey&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;validApiKeys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unauthorized&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in your Express app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;apiKeyMiddleware&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./middleware/apiKey.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;apiKeyMiddleware&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello, world!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server running on port 3000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧠 A Few Tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Store API keys in a &lt;strong&gt;database&lt;/strong&gt; (with metadata like usage, owner, status).&lt;/li&gt;
&lt;li&gt;Add &lt;strong&gt;rate limiting&lt;/strong&gt; to prevent abuse.&lt;/li&gt;
&lt;li&gt;Consider &lt;strong&gt;rotating&lt;/strong&gt; keys over time.&lt;/li&gt;
&lt;li&gt;Log each request to track usage per key.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ⚡ Want to Skip the Boilerplate?
&lt;/h2&gt;

&lt;p&gt;If you don’t want to build all this from scratch, you can use a tool like &lt;a href="https://app.limitly.dev/" rel="noopener noreferrer"&gt;Limitly&lt;/a&gt; — it handles API key creation, validation, usage limits (daily, weekly, etc.), and request tracking with an SDK you can plug into your Express app.&lt;/p&gt;

&lt;p&gt;I built it because I was tired of reinventing this every time I launched an API.&lt;/p&gt;




&lt;p&gt;Let me know if you use a different method or have feedback — always happy to learn new approaches!&lt;/p&gt;

</description>
      <category>api</category>
      <category>programming</category>
      <category>webdev</category>
      <category>express</category>
    </item>
    <item>
      <title>Supadex: A Mobile Dashboard for Supabase Developers 🚀</title>
      <dc:creator>Guillermo Olcina Martínez</dc:creator>
      <pubDate>Wed, 11 Jun 2025 10:13:45 +0000</pubDate>
      <link>https://forem.com/guiolmar/supadex-a-mobile-dashboard-for-supabase-developers-5973</link>
      <guid>https://forem.com/guiolmar/supadex-a-mobile-dashboard-for-supabase-developers-5973</guid>
      <description>&lt;p&gt;Hey DEV community! 👋&lt;/p&gt;

&lt;p&gt;If you’re building apps with &lt;strong&gt;Supabase&lt;/strong&gt;, you know how powerful it is as a Postgres-based backend. But what if you could &lt;strong&gt;monitor and manage your Supabase projects directly from your phone&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;That’s exactly why I built &lt;strong&gt;Supadex&lt;/strong&gt; — a mobile companion for developers who want real-time visibility and control over their Supabase instances, even when they’re away from their laptop.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚦 Why Supadex?
&lt;/h2&gt;

&lt;p&gt;Supabase is amazing, but if you've ever tried to quickly check a query result or manage a storage bucket while commuting or in a meeting, you know it's not super mobile-friendly.&lt;/p&gt;

&lt;p&gt;Supadex solves that.&lt;/p&gt;

&lt;p&gt;With Supadex, you get a &lt;strong&gt;native mobile dashboard&lt;/strong&gt; that connects securely to your Supabase projects and offers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🔍 &lt;strong&gt;Real-time Analytics&lt;/strong&gt;: Keep an eye on REST and Auth requests, track usage, and monitor active users — all from your phone.&lt;/li&gt;
&lt;li&gt;🗃️ &lt;strong&gt;Database Management&lt;/strong&gt;: Browse tables, write SQL, save your favorite queries, and run them on the go.&lt;/li&gt;
&lt;li&gt;📁 &lt;strong&gt;Storage Tools&lt;/strong&gt;: Navigate buckets, manage files, share public URLs — faster than opening your laptop.&lt;/li&gt;
&lt;li&gt;🔒 &lt;strong&gt;Privacy-first Approach&lt;/strong&gt;: Tokens are stored &lt;em&gt;locally&lt;/em&gt; only. No data collection, no tracking. You stay in control.&lt;/li&gt;
&lt;li&gt;⚙️ &lt;strong&gt;Developer Quality of Life&lt;/strong&gt;: Multi-project support, dark mode, and real-time updates with a smooth interface.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  👨‍💻 Who is Supadex for?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Supabase developers (obviously)&lt;/li&gt;
&lt;li&gt;Backend engineers working remotely or on-call&lt;/li&gt;
&lt;li&gt;DevOps folks who need to check logs/stats quickly&lt;/li&gt;
&lt;li&gt;Full-stack devs who don’t want to SSH into a VPS just to check a DB&lt;/li&gt;
&lt;li&gt;Anyone who builds side-projects and wants easy access to Supabase on mobile&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📲 Pricing
&lt;/h2&gt;

&lt;p&gt;Supadex is a premium tool, but it comes with flexible options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;$3.99/month&lt;/li&gt;
&lt;li&gt;$39.99/year&lt;/li&gt;
&lt;li&gt;Or a $79.99 lifetime plan&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of it as paying for peace of mind (and fewer rushed logins to the Supabase web UI in weird places 😅).&lt;/p&gt;




&lt;h2&gt;
  
  
  🔗 Try it out
&lt;/h2&gt;

&lt;p&gt;If you use Supabase regularly and want more control on the go, give &lt;strong&gt;Supadex&lt;/strong&gt; a try. I’d love your feedback or suggestions — I’m actively improving it!&lt;/p&gt;

&lt;p&gt;→ &lt;a href="https://apps.apple.com/es/app/supadex-monitor-for-supabase/id6741071194" rel="noopener noreferrer"&gt;Download Supadex on the App Store 🍎&lt;/a&gt;&lt;br&gt;&lt;br&gt;
→ &lt;a href="https://play.google.com/store/apps/details?id=com.guiolmar.supadex" rel="noopener noreferrer"&gt;Download Supadex on the Play Store 🤖&lt;/a&gt;&lt;br&gt;&lt;br&gt;
→ &lt;a href="https://www.supadex.app" rel="noopener noreferrer"&gt;Visit the website&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Let me know what you think — happy to answer any questions or dive into how I built it, if that’s helpful!&lt;/p&gt;

&lt;p&gt;Cheers,&lt;br&gt;&lt;br&gt;
&lt;em&gt;– Guillermo Olcina&lt;/em&gt; 🧑‍💻&lt;/p&gt;

</description>
      <category>supabase</category>
      <category>database</category>
      <category>postgres</category>
      <category>reactnative</category>
    </item>
  </channel>
</rss>
