<?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" version="2.0"><channel><title><![CDATA[Authorizer Blog]]></title><description><![CDATA[Authorizer is an open-source & database independent authentication and authorization solution.]]></description><link>https://blog.authorizer.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1669443440849/QDLxUZREo.png</url><title>Authorizer Blog</title><link>https://blog.authorizer.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Sat, 05 Sep 2026 08:06:15 GMT</lastBuildDate><atom:link href="https://blog.authorizer.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Authorizer 2.4: Open-source auth for AI agents and modern enterprise apps]]></title><description><![CDATA[Product Hunt · GitHub . Website . Docs
Authorizer 2.4.0 is out.
I've been working on Authorizer for a few years, and 2.4 is one of the biggest releases I've worked on so far.
A big part of this releas]]></description><link>https://blog.authorizer.dev/authorizer-2-4-open-source-auth-for-ai-agents-and-modern-enterprise-apps</link><guid isPermaLink="true">https://blog.authorizer.dev/authorizer-2-4-open-source-auth-for-ai-agents-and-modern-enterprise-apps</guid><category><![CDATA[AI]]></category><category><![CDATA[#ai-tools]]></category><category><![CDATA[ai agents]]></category><category><![CDATA[agents]]></category><category><![CDATA[Developer Tools]]></category><category><![CDATA[mcp]]></category><category><![CDATA[Auth ]]></category><category><![CDATA[Security]]></category><category><![CDATA[OSS]]></category><category><![CDATA[product hunt]]></category><dc:creator><![CDATA[Lakhan Samani]]></dc:creator><pubDate>Wed, 02 Sep 2026 06:32:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/580f234f5fec191d85b1524a/35915e67-1007-4ed3-bd02-8dcc83bf149d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a href="https://www.producthunt.com/products/authorizer?launch=authorizer-2">Product Hunt</a> · <a href="https://github.com/authorizerdev/authorizer">GitHub</a> . <a href="https://authorizer.dev">Website</a> . <a href="https://docs.authorizer.dev">Docs</a></p>
<p>Authorizer 2.4.0 is out.</p>
<p>I've been working on Authorizer for a few years, and 2.4 is one of the biggest releases I've worked on so far.</p>
<p>A big part of this release came from a simple problem:</p>
<p><strong>Authentication is no longer only about users.</strong></p>
<p>Applications also need to deal with services, workloads, organizations, and AI agents.</p>
<p>At the same time, enterprise applications still need things like SSO, SCIM, passkeys, multi-tenant identity, and fine-grained authorization.</p>
<p>With 2.4, I wanted Authorizer to handle both sides of that problem.</p>
<h2>What's new in Authorizer 2.4?</h2>
<p>The release adds quite a lot, but these are the areas I'm most excited about:</p>
<ul>
<li>OAuth 2.1 and MCP support</li>
<li>Service accounts and machine-to-machine authentication</li>
<li>Agent-to-agent delegation</li>
<li>Workload identity</li>
<li>WebAuthn and passkeys</li>
<li>SAML and OIDC SSO</li>
<li>SCIM 2.0 user and group provisioning</li>
<li>Organizations and multi-tenant identity</li>
<li>Fine-grained authorization with OpenFGA</li>
<li>GraphQL, REST, gRPC, and MCP APIs</li>
<li>A redesigned MFA flow</li>
<li>OAuth and security hardening</li>
</ul>
<p>You can see the complete list in the <a href="https://github.com/authorizerdev/authorizer/blob/main/CHANGELOG.md#240---2026-08-19">2.4.0 changelog</a>.</p>
<hr />
<h2>Authentication for AI agents</h2>
<p>One of the biggest areas I worked on in this release is authentication for AI agents.</p>
<p>An agent isn't a user, but it still needs an identity.</p>
<p>It may need to call an API, access an MCP server, act on behalf of a user, or communicate with another agent.</p>
<p>That creates a different set of authentication and authorization problems.</p>
<p>Authorizer 2.4 adds support for:</p>
<ul>
<li>OAuth 2.1</li>
<li>Remote MCP servers</li>
<li>Dynamic Client Registration</li>
<li>Client ID Metadata Documents</li>
<li>Service accounts</li>
<li>Machine-to-machine authentication</li>
<li>Agent-to-agent delegation</li>
<li>OAuth token exchange</li>
<li>Delegated tokens with actor chains</li>
</ul>
<p>For MCP, Authorizer can expose its MCP surface over Streamable HTTP and protect it with OAuth 2.1.</p>
<p>Tokens are audience-bound to the MCP endpoint, so a token intended for the MCP server isn't treated as a general-purpose Authorizer credential.</p>
<p>Learn more in the <a href="https://docs.authorizer.dev/core/mcp/">MCP documentation</a>.</p>
<hr />
<h2>Service accounts and workload identity</h2>
<p>Not every request comes from a person.</p>
<p>Background workers, services, CI jobs, Kubernetes workloads, and other systems need to authenticate too.</p>
<p>Authorizer 2.4 adds first-class service accounts using the OAuth <code>client_credentials</code> flow.</p>
<p>Service accounts can also use workload identity mechanisms including:</p>
<ul>
<li>RFC 7523 JWT bearer assertions</li>
<li>SPIFFE JWT-SVID</li>
<li>Kubernetes TokenReview</li>
</ul>
<p>This means workloads don't necessarily have to depend on long-lived static credentials.</p>
<p>Service accounts also become first-class subjects in the authorization layer, which makes it possible to apply authorization rules to machines in much the same way as users.</p>
<hr />
<h2>Agent-to-agent delegation</h2>
<p>Another interesting part of 2.4 is agent-to-agent delegation.</p>
<p>An agent can act on behalf of a user without simply receiving the user's full access.</p>
<p>Authorizer uses OAuth token exchange (RFC 8693) to create delegated tokens.</p>
<p>The resulting token carries information about the actor chain and can have a reduced scope.</p>
<p>For example:</p>
<pre><code class="language-text">User
  ↓
Agent A
  ↓
Agent B
</code></pre>
<p>Each step can have fewer permissions than the previous one.</p>
<p>The effective scope is limited by the permissions available to the user, the agent, and the requested scope.</p>
<p>This makes delegation more explicit than passing around a user's original access token.</p>
<hr />
<h2>Enterprise SSO</h2>
<p>The other major part of this release is enterprise identity.</p>
<p>Authorizer 2.4 adds support for:</p>
<ul>
<li>SAML 2.0</li>
<li>OIDC federation</li>
<li>SAML Identity Provider</li>
<li>SAML Service Provider</li>
<li>Verified email domains</li>
<li>Home realm discovery</li>
<li>Organization-level SSO configuration</li>
<li>SCIM 2.0 provisioning</li>
</ul>
<p>Organizations can configure their own identity providers and manage users within their own tenant.</p>
<p>For example, an organization can connect its existing identity provider and provision users through SCIM rather than requiring administrators to manage every user manually.</p>
<p>Authorizer can also act as a SAML IdP when other SaaS applications need to authenticate against it.</p>
<hr />
<h2>SCIM 2.0</h2>
<p>SCIM is another area that became important for enterprise deployments.</p>
<p>Authorizer 2.4 supports SCIM 2.0 user provisioning as well as SCIM groups.</p>
<p>This allows identity providers such as Okta and Entra to provision and deprovision users.</p>
<p>Groups can also be connected to authorization rules through OpenFGA.</p>
<p>That gives you a path from:</p>
<pre><code class="language-text">Identity Provider
      ↓
     SCIM
      ↓
   Users / Groups
      ↓
    OpenFGA
      ↓
Application permissions
</code></pre>
<hr />
<h2>Passkeys and WebAuthn</h2>
<p>2.4 also adds WebAuthn and passkey support.</p>
<p>Users can authenticate using platform authenticators such as:</p>
<ul>
<li>Touch ID</li>
<li>Face ID</li>
<li>Windows Hello</li>
</ul>
<p>It also supports FIDO2 security keys, usernameless discoverable login, and using passkeys as an MFA factor.</p>
<p>The MFA flow itself was also redesigned in this release.</p>
<hr />
<h2>Fine-grained authorization with OpenFGA</h2>
<p>Authentication tells you <strong>who someone is</strong>.</p>
<p>Authorization answers a different question:</p>
<p><strong>What are they allowed to do?</strong></p>
<p>Authorizer 2.4 uses an embedded OpenFGA-based relationship authorization engine.</p>
<p>This lets you model relationships such as:</p>
<pre><code class="language-text">user:lakhan
    ↓ member
organization:acme
    ↓ owns
project:authorizer
</code></pre>
<p>And then make permission checks based on those relationships.</p>
<p>The FGA engine can run embedded or use an external OpenFGA store, depending on the deployment.</p>
<hr />
<h2>More ways to use the API</h2>
<p>Authorizer 2.4 expands the public API surface across:</p>
<ul>
<li>GraphQL</li>
<li>REST</li>
<li>gRPC</li>
<li>MCP</li>
</ul>
<p>The goal here is fairly simple: use the interface that makes sense for your application without having to build a separate authentication layer around it.</p>
<p>The underlying service layer is shared across these transports.</p>
<hr />
<h2>Built for self-hosting</h2>
<p>Authorizer remains open source and self-hostable.</p>
<p>You can run it yourself and keep control over your authentication and authorization infrastructure.</p>
<p>If you want to try it, the easiest place to start is the <a href="https://docs.authorizer.dev/getting-started/">Getting Started guide</a>.</p>
<hr />
<h2>Security was a big part of this release too</h2>
<p>A lot of the work in 2.4 isn't visible in a product screenshot.</p>
<p>There are several OAuth and security hardening changes in this release, including:</p>
<ul>
<li>SSRF-hardened external fetches</li>
<li>OAuth 2.1 hardening</li>
<li>RFC 8707 audience binding for MCP</li>
<li>Stricter client authentication</li>
<li>Improved token validation</li>
<li>Workload identity validation</li>
<li>Rate-limit fail-closed option</li>
<li>OIDC discovery and JWKS caching</li>
<li>A separate encryption key for secrets stored at rest</li>
</ul>
<p>There are also breaking configuration changes in 2.4, including the requirement to provide a canonical <code>--url</code> and, for certain JWT configurations, an explicit <code>--encryption-key</code>.</p>
<p>If you're upgrading an existing deployment, I strongly recommend reading the <a href="https://github.com/authorizerdev/authorizer/blob/main/CHANGELOG.md#240---2026-08-19">2.4.0 changelog</a> before upgrading.</p>
<hr />
<h2>Why I built this</h2>
<p>I've spent a lot of time working on authentication over the years.</p>
<p>The problems have changed.</p>
<p>A few years ago, the main question was usually:</p>
<blockquote>
<p>How do I authenticate users in my application?</p>
</blockquote>
<p>Today, that is only part of the problem.</p>
<p>You may also have:</p>
<ul>
<li>APIs talking to other APIs</li>
<li>background services</li>
<li>Kubernetes workloads</li>
<li>enterprise identity providers</li>
<li>multiple organizations</li>
<li>AI agents</li>
<li>agents acting on behalf of users</li>
<li>MCP servers</li>
<li>fine-grained permissions</li>
</ul>
<p>I wanted Authorizer to be useful for these cases without requiring developers to assemble a different identity product for every one of them.</p>
<p>That's a big reason why 2.4 ended up being such a large release.</p>
<hr />
<h2>Try Authorizer 2.4</h2>
<p>If you're building a SaaS product, API, enterprise application, or AI-enabled application, I'd love for you to try it.</p>
<p><strong>Website:</strong> <a href="https://authorizer.dev/">https://authorizer.dev/</a></p>
<p><strong>Documentation:</strong> <a href="https://docs.authorizer.dev/">https://docs.authorizer.dev/</a></p>
<p><strong>Get started:</strong> <a href="https://docs.authorizer.dev/getting-started/">https://docs.authorizer.dev/getting-started/</a></p>
<p><strong>GitHub:</strong> <a href="https://github.com/authorizerdev/authorizer">https://github.com/authorizerdev/authorizer</a></p>
<p><strong>What's new in 2.4.0:</strong> <a href="https://github.com/authorizerdev/authorizer/blob/main/CHANGELOG.md#240---2026-08-19">https://github.com/authorizerdev/authorizer/blob/main/CHANGELOG.md#240---2026-08-19</a></p>
<p><strong>Release video:</strong> <a href="https://youtu.be/X0RA-sP8Z5I">https://youtu.be/X0RA-sP8Z5I</a></p>
<p>If you try it, I'd genuinely like to hear what works, what doesn't, and what you'd like to see next.</p>
<hr />
<h2>About Authorizer</h2>
<p>Authorizer is an open-source authentication and authorization platform for modern applications.</p>
<p>It provides authentication, authorization, enterprise SSO, passkeys, SCIM, organizations, machine-to-machine authentication, and APIs across GraphQL, REST, gRPC, and MCP.</p>
<p><strong>GitHub:</strong> <a href="https://github.com/authorizerdev/authorizer">https://github.com/authorizerdev/authorizer</a></p>
<p><strong>Website:</strong> <a href="https://authorizer.dev/">https://authorizer.dev/</a></p>
]]></content:encoded></item><item><title><![CDATA[Your AI assistant can leak files people aren't allowed to see — here's how to fix it]]></title><description><![CDATA[TL;DR

Vector search ignores your permission model: an engineer can ask your RAG assistant about board-level financials and get them, because semantically close = retrieved, and a restricted chunk in ]]></description><link>https://blog.authorizer.dev/permission-aware-rag-authorizer-openfga-qdrant</link><guid isPermaLink="true">https://blog.authorizer.dev/permission-aware-rag-authorizer-openfga-qdrant</guid><category><![CDATA[Open Source]]></category><category><![CDATA[AI]]></category><category><![CDATA[RAG ]]></category><category><![CDATA[authorization]]></category><category><![CDATA[authentication]]></category><category><![CDATA[vector database]]></category><category><![CDATA[vector embeddings]]></category><category><![CDATA[Vector Search]]></category><category><![CDATA[qdrant]]></category><dc:creator><![CDATA[Lakhan Samani]]></dc:creator><pubDate>Tue, 16 Jun 2026 14:00:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/580f234f5fec191d85b1524a/c1716034-3d8e-4a7c-b2c5-83e975574e08.svg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p><strong>TL;DR</strong></p>
<ul>
<li><p>Vector search ignores your permission model: an engineer can ask your RAG assistant about board-level financials and get them, because semantically close = retrieved, and a restricted chunk in the prompt can't be un-read.</p>
</li>
<li><p>Fix it with a <strong>pre-filter</strong>: Authorizer's embedded OpenFGA answers <code>list_permissions</code> with the <em>user's</em> token, and that allow-list becomes a Qdrant <code>must</code> payload filter — forbidden chunks are never scored.</p>
</li>
<li><p>Revocation is one tuple deletion, effective on the next question. No re-indexing, no re-login.</p>
</li>
<li><p>Verified live: 63 tests green (including a dedicated fail-closed permission suite), official <code>quay.io/authorizer/authorizer:2.3.0</code> image, real grant/revoke cycle. Run it: <code>docker compose up -d &amp;&amp; python scripts/fga_seed.py &amp;&amp; python scripts/fga_demo.py --llm</code>.</p>
</li>
</ul>
</blockquote>
<hr />
<p>There's a quiet security regression happening in almost every company shipping AI features right now.</p>
<p>You spent years getting access control right. Row-level security in Postgres. Folder permissions in Drive. Channel membership in Slack. Then someone embedded all of it into a vector database, pointed an LLM at it, and called it a knowledge assistant.</p>
<p>The assistant doesn't know about your permission model. Similarity search returns whatever is <em>semantically close</em> — the intern asking "how do raises work?" gets chunks of the compensation memo, because cosine similarity has no concept of "need to know." And once a restricted chunk lands in the prompt, it's over: you cannot redact what the model has already read.</p>
<p>The common fix is a <em>post-filter</em>: run the vector search first, <strong>then</strong> check each result against your permission system and drop what the user shouldn't see. Most off-the-shelf "permission-aware retriever" wrappers work exactly this way. It's better than nothing, but the forbidden chunks were still scored, fetched, and held in your application's memory before being discarded — and if 3 of your top-4 results get dropped, your agent answers from a starved context. When the checks run against a hosted authorization service, you also pay a network round trip per result, and your company's entire who-can-see-what graph lives on someone else's infrastructure.</p>
<p>We built it the other way around — as a <strong>pre-filter</strong>, fully self-hosted, on an open-source stack — and shipped it as a runnable demo. The demo's knowledge base belongs to a fictional <strong>ACME Corp</strong> and holds four documents: a public onboarding guide, an engineering tech-stack doc, a finance-only Q4 financial report, and a security policy. Picture the most relatable version of the leak: <strong>an engineer asking the assistant about company financials.</strong> Same question, two users, different answers. Here's the actual output:</p>
<pre><code class="language-plaintext">👤 alice@example.com   (engineering)   may view: onboarding_guide.txt, tech_stack.txt
   ❓ What was our Q4 revenue and cash runway?
   💬 I don't have enough information in the knowledge base to answer this question.

👤 carol@example.com   (finance)       may view: financial_report.txt, onboarding_guide.txt
   ❓ What was our Q4 revenue and cash runway?
   💬 The Q4 revenue for ACME Corp was \(14.2M, and the monthly cash burn is \)1.1M —
      a 26-month runway at current burn.
</code></pre>
<p>Alice isn't being told "access denied." ACME's financial report simply does not exist in her world — it was never a search candidate, never retrieved, never in the prompt. The model cannot leak what it never saw. Carol, who's on the finance team, gets the number.</p>
<p>Here's the use case at a glance — the same question, the two outcomes, and the open-source stack underneath:</p>
<img src="https://cdn.hashnode.com/uploads/covers/580f234f5fec191d85b1524a/dba13d70-2675-4b7d-a39b-7b171df2f0df.svg" alt="" style="display:block;margin:0 auto" />

<h2>The stack — open source end to end</h2>
<p>Every piece runs on your hardware, and each one earns its place:</p>
<ul>
<li><p><a href="https://github.com/authorizerdev/authorizer"><strong>Authorizer</strong></a> (≥ v2.3.0) — open-source authentication <em>and</em> authorization in one Go binary. It embeds an <a href="https://openfga.dev">OpenFGA</a> engine (the open-source implementation of Google's Zanzibar relationship-based access control), so the server that issues your users' tokens also answers "can this user view this document?" — in-process, no extra service to deploy.</p>
</li>
<li><p><a href="https://qdrant.tech"><strong>Qdrant</strong></a> — the vector database whose <a href="https://qdrant.tech/documentation/concepts/filtering/">payload filters</a> make true pre-filtering possible: a <code>must</code> condition is evaluated <em>during</em> the HNSW vector search, not bolted on after. This single feature is what lets the permission boundary live inside the retrieval step. Its built-in dashboard (<code>/dashboard</code>) also lets you inspect exactly which chunks and payloads exist.</p>
</li>
<li><p><a href="https://qdrant.github.io/fastembed/"><strong>FastEmbed</strong></a> — local ONNX embeddings (<code>BAAI/bge-small-en-v1.5</code>, 384 dimensions, ~25 MB). No embedding API, no per-token costs, works offline after the first download.</p>
</li>
<li><p><a href="https://ollama.com"><strong>Ollama</strong></a> — the local LLM (<code>llama3.2</code> in the demo). Prompts containing your internal documents never leave the machine.</p>
</li>
<li><p><a href="https://gradio.app"><strong>Gradio</strong></a> — the demo's web UI, now with a login row so each person chats as themselves.</p>
</li>
</ul>
<p>Nothing in this chain phones home: not the documents, not the tokens, not the permission graph, not the prompts.</p>
<pre><code class="language-bash">docker compose up -d              # Qdrant + Authorizer (quay.io/authorizer/authorizer:2.3.0)
python scripts/fga_seed.py        # demo users, authorization model, grants
python scripts/fga_demo.py --llm  # watch two users get different answers
</code></pre>
<h2>Permissions are relationships, not roles</h2>
<p>The document side of the authorization model is six lines of OpenFGA DSL:</p>
<pre><code class="language-dsl">type document
  relations
    define owner: [user]
    define viewer: [user, user:*, team#member]
    define blocked: [user]
    define can_view: (viewer or owner) but not blocked
</code></pre>
<p>Access is granted by writing <em>facts</em>, not code:</p>
<pre><code class="language-text">user:*                    viewer   document:onboarding_guide.txt   # public
team:engineering#member   viewer   document:tech_stack.txt         # a team, not a user list
team:finance#member       viewer   document:financial_report.txt   # finance only
team:security#member      viewer   document:security_policy.txt
user:&lt;alice&gt;              member   team:engineering
user:&lt;carol&gt;              member   team:finance
</code></pre>
<p>That <code>team:finance#member viewer</code> tuple is the whole ballgame for our example: Alice is a member of <code>team:engineering</code>, not <code>team:finance</code>, so she has no path to <code>document:financial_report.txt</code>. Carol does.</p>
<p>Notice what's <em>not</em> here: no changes to the ingestion pipeline, no per-user collections, no ACL columns bolted onto chunk metadata. Each Qdrant chunk already carries its source filename in the payload — the FGA object is simply <code>document:&lt;that filename&gt;</code>. The payload you already have is the join key.</p>
<h2>How does it work? The architecture</h2>
<p>Under the hood it's one Python app process talking to three local servers. The important part is the <em>order</em>: the permission check happens <strong>before</strong> the vector search, so off-limits files are never even embedded into the candidate set.</p>
<img src="https://cdn.hashnode.com/uploads/covers/580f234f5fec191d85b1524a/543cdfb5-1189-4eb7-8560-6cdfcf0845f5.svg" alt="" style="display:block;margin:0 auto" />

<p>It comes down to two API calls.</p>
<p><strong>One:</strong> before searching, ask Authorizer what this user may see — authenticated with the <em>user's own token</em>:</p>
<pre><code class="language-python">allowed = authz.allowed_documents(user_token)
# GraphQL: list_permissions(relation: "can_view", object_type: "document")
# Alice (engineering) → ["onboarding_guide.txt", "tech_stack.txt"]   # no financial_report
</code></pre>
<p><strong>Two:</strong> hand that allow-list to Qdrant as a <code>must</code> condition:</p>
<pre><code class="language-python">FieldCondition(key="source", match=MatchAny(any=allowed))
</code></pre>
<p>Qdrant evaluates the condition during HNSW traversal. Forbidden vectors are never candidates — top-k stays full of the best chunks the user <em>may</em> see, instead of being decimated by after-the-fact redaction.</p>
<p>And because the permission call carries the end user's JWT, Authorizer pins the subject server-side. An explicit "check as someone else" is rejected unless the caller is a super-admin. A fully prompt-injected agent has nothing to escalate with: it asks as Alice, it gets Alice's answer — and Alice can't see finance.</p>
<h2>Fail closed, or don't bother</h2>
<p>The demo treats every ambiguous state as <em>deny</em>:</p>
<ul>
<li><p>Authorizer unreachable → <code>AuthorizationError</code>, not an unrestricted search.</p>
</li>
<li><p>Authorization configured but no token supplied → error, not a silent bypass.</p>
</li>
<li><p>Permission list truncated → refuse, a partial allow-list is not the full one.</p>
</li>
<li><p>Empty allow-list → refusal answer <em>without ever calling the LLM</em>.</p>
</li>
<li><p>And after generation, the cited sources are batch re-checked with <code>check_permissions</code> — a grant revoked mid-request raises instead of leaking.</p>
</li>
</ul>
<p>That last list is about 30 lines of code total. It's the difference between a security feature and a security theater feature.</p>
<h2>Revocation that actually revokes</h2>
<p>The demo's second act grants Bob engineering access — one tuple write — and his very next question retrieves the tech-stack doc. Then it deletes the tuple:</p>
<pre><code class="language-plaintext">⚡ Granting: bob → member → team:engineering
👤 bob   may view: onboarding_guide.txt, tech_stack.txt    ← immediately

⚡ Revoking the same tuple
👤 bob   may view: onboarding_guide.txt                    ← immediately
</code></pre>
<p>No re-embedding. No re-indexing. No re-login. No "takes effect after the nightly sync." Permissions live in tuples, not in the vector index — offboarding a contractor is one <code>_fga_delete_tuples</code> call, and their next question is denied.</p>
<h2>What we verified (and what we'd tell you anyway)</h2>
<p>This isn't a whiteboard architecture. The demo ships a dedicated fail-closed permission suite (authz client, Qdrant pre-filter semantics, pipeline enforcement) — the full suite is <strong>63 tests, all green</strong> — and the whole flow ran live against the official <code>quay.io/authorizer/authorizer:2.3.0</code> image, including the grant/revocation cycle above.</p>
<p>Honest notes from the build: <code>list_permissions</code> caps at 1,000 objects (the client fails closed on truncation — model access via teams/folders to stay under it); contextual tuples work on checks but not on the list call; and Authorizer's CSRF guard requires an <code>Origin</code> header on server-side POSTs — your reverse proxy or HTTP client needs to send one.</p>
<h2>FAQ</h2>
<h3>Do I need to re-index Qdrant when permissions change?</h3>
<p>No. Permissions live in OpenFGA relationship tuples, not in the vector index. Granting access is one <code>_fga_write_tuples</code> call and revoking is one <code>_fga_delete_tuples</code> call — both take effect on the user's very next question. The embeddings, payloads, and collections in Qdrant are never touched.</p>
<h3>What happens if Authorizer is unreachable mid-request?</h3>
<p>The pipeline fails closed: the permission client raises an error and the user gets no documents — never all documents. The same applies to expired tokens, missing tokens when authorization is enabled, and truncated permission lists. Treating every ambiguous state as "deny" is roughly 30 lines of code in the demo.</p>
<h3>Can a prompt-injected agent bypass the filter?</h3>
<p>No. The agent calls Authorizer with the end user's own JWT, and the server pins the permission subject from that token — a "check as someone else" parameter is rejected unless the caller is a super-admin. A hijacked agent holds no privileged credential, so it asks as the user and gets the user's answer: denied.</p>
<h3>Does this work with LangChain or LlamaIndex?</h3>
<p>The demo's permission calls go through the official <a href="https://github.com/authorizerdev/authorizer-py"><code>authorizer-py</code></a> SDK — <code>login</code>, <code>check_permissions</code>, <code>list_permissions</code>, all typed and fail-closed. There's no dedicated LangChain/LlamaIndex retriever wrapper yet, but the pattern (allow-list → vector-store metadata filter) ports directly to any retriever that supports pre-search filtering — Qdrant's LangChain and LlamaIndex integrations both expose payload filters. The demo's <code>authz.py</code> is the thin glue, and packaging it as a reusable retriever is the obvious next step.</p>
<h3>What are the current limits?</h3>
<p><code>list_permissions</code> caps at 1,000 objects per call (the client fails closed on truncation — model access via teams or folders to stay under it). Contextual tuples work on <code>check_permissions</code> but not on the list call, parameterized CEL conditions aren't exposed through the API, and the embedded FGA engine needs a SQL datastore.</p>
<h2>Run the demo yourself, in four steps</h2>
<p><strong>Step 1 — Start the tools.</strong> One command brings up Qdrant and Authorizer (with its embedded OpenFGA engine):</p>
<pre><code class="language-bash">docker compose up -d        # Qdrant on :6333, Authorizer on :8080
</code></pre>
<p><strong>Step 2 — Seed ACME's users and permissions.</strong> The seed script is idempotent: it signs up the three demo users, installs the authorization model, and writes the relationship tuples — all skipped on re-runs.</p>
<pre><code class="language-bash">python scripts/fga_seed.py
# ✓ Created users alice (engineering), carol (finance), bob (new hire)
# ✓ Installed authorization model
# ✓ Granted: team:finance#member viewer document:financial_report.txt …
</code></pre>
<p>This produces ACME's access matrix:</p>
<table>
<thead>
<tr>
<th>document</th>
<th>alice (eng)</th>
<th>bob (new hire)</th>
<th>carol (finance)</th>
</tr>
</thead>
<tbody><tr>
<td><code>onboarding_guide.txt</code></td>
<td>✅</td>
<td>✅</td>
<td>✅</td>
</tr>
<tr>
<td><code>tech_stack.txt</code></td>
<td>✅</td>
<td>❌</td>
<td>❌</td>
</tr>
<tr>
<td><code>financial_report.txt</code></td>
<td>❌</td>
<td>❌</td>
<td>✅</td>
</tr>
<tr>
<td><code>security_policy.txt</code></td>
<td>❌</td>
<td>❌</td>
<td>❌</td>
</tr>
</tbody></table>
<p><strong>Step 3 — Log in.</strong> Launch the UI; it asks you to log in first (it can't answer anything until it knows who you are), with the demo accounts shown right on the page:</p>
<pre><code class="language-bash">python src/app.py --authorizer http://localhost:8080
</code></pre>
<blockquote>
<p>Log in as <code>alice@example.com</code> (engineering) or <code>carol@example.com</code> (finance), password <code>Demo@Pass123</code>. The login screen is shown first — the credentials are verified against Authorizer, and the chat only appears once you're authenticated.</p>
</blockquote>
<p><strong>Step 4 — Ask the same question as different people.</strong> Ask <em>"What was our Q4 revenue?"</em> as Alice and you get <em>"I don't have enough information"</em> — the financial report was never retrieved. Ask Carol and she gets ACME's $14.2M. Prefer the terminal? <code>python scripts/fga_demo.py --llm</code> runs the whole comparison, including a live grant-and-revoke.</p>
<h3>Links</h3>
<ul>
<li><p><strong>Demo</strong>: <a href="https://github.com/lakhansamani/qdrant-rag-llm-example/tree/main">https://github.com/lakhansamani/qdrant-rag-llm-example/tree/main</a></p>
</li>
<li><p><strong>FGA guide</strong> (models, patterns, full DSL reference): <a href="https://docs.authorizer.dev/core/fga-guide">https://docs.authorizer.dev/core/fga-guide</a></p>
</li>
<li><p><strong>Authorization API</strong>: <a href="https://docs.authorizer.dev/core/graphql-api">https://docs.authorizer.dev/core/graphql-api</a></p>
</li>
<li><p><strong>GitHub</strong>: <a href="https://github.com/authorizerdev/authorizer">https://github.com/authorizerdev/authorizer</a> ⭐</p>
</li>
<li><p><strong>SDKs</strong>: <a href="https://github.com/authorizerdev/authorizer-py">Python</a> (used in this demo) · <a href="https://docs.authorizer.dev/sdks/authorizer-go">Go</a> · <a href="https://docs.authorizer.dev/sdks/authorizer-js">JavaScript</a> — <code>check_permissions</code> / <code>list_permissions</code> Ship in all three.</p>
</li>
<li><p><strong>Discord</strong>: <a href="https://discord.gg/3Jse9RtS">https://discord.gg/3Jse9RtS</a></p>
</li>
</ul>
<p>Your agents are only as trustworthy as the boundaries you give them. Give them real ones — on your own hardware.</p>
]]></content:encoded></item><item><title><![CDATA[Authorizer v2 Is Here: Self-Hosted Auth, Rebuilt From the Ground Up]]></title><description><![CDATA[We just shipped Authorizer v2 — a major rewrite of our open-source, self-hosted authentication and authorization server.
If you've ever been frustrated by per-seat auth pricing, vendor lock-in, or shi]]></description><link>https://blog.authorizer.dev/authorizer-v2-is-here-self-hosted-auth-rebuilt-from-the-ground-up</link><guid isPermaLink="true">https://blog.authorizer.dev/authorizer-v2-is-here-self-hosted-auth-rebuilt-from-the-ground-up</guid><category><![CDATA[Open Source]]></category><category><![CDATA[authentication]]></category><category><![CDATA[authorization]]></category><category><![CDATA[AI]]></category><category><![CDATA[free]]></category><category><![CDATA[Go Language]]></category><category><![CDATA[architecture]]></category><dc:creator><![CDATA[Lakhan Samani]]></dc:creator><pubDate>Thu, 02 Apr 2026 10:08:43 GMT</pubDate><content:encoded><![CDATA[<p>We just shipped <strong>Authorizer v2</strong> — a major rewrite of our open-source, self-hosted authentication and authorization server.</p>
<p>If you've ever been frustrated by per-seat auth pricing, vendor lock-in, or shipping your users' data to someone else's cloud — this release is for you.</p>
<p><strong>TL;DR</strong>: Single Go binary. 13+ database backends. CLI-driven config. OAuth 2.0/OIDC compliant. Deploy in 5 minutes. Free forever.</p>
<p><a href="https://github.com/authorizerdev/authorizer">GitHub</a> | <a href="https://docs.authorizer.dev">Docs</a> | <a href="https://authorizer.dev">Website</a> | <a href="https://www.youtube.com/watch?v=aQrpYCyrDjU">Migration Video</a></p>
<hr />
<h2>Why We Built v2</h2>
<p>Authorizer v1 worked. Teams used it in production. But we kept hearing the same feedback:</p>
<blockquote>
<p>"Config stored in the database felt fragile." "I want to manage auth config the same way I manage everything else — through code." "It's hard to audit what changed and when."</p>
</blockquote>
<p>So we rethought the entire configuration model.</p>
<p><strong>v1</strong>: Configuration lived in the database, encrypted. You changed settings through the dashboard UI or a GraphQL mutation. Convenient, but opaque — you couldn't version-control your auth config, couldn't audit changes easily, and secrets sat in a persistent store.</p>
<p><strong>v2</strong>: <strong>All configuration is passed via CLI flags at startup.</strong> That's it. No <code>.env</code> files. No database-stored config. No mutation to accidentally expose secrets. Your auth server is configured the same way you configure every other 12-factor service.</p>
<pre><code class="language-bash">authorizer \
  --database-type postgres \
  --database-url "postgres://user:pass@localhost:5432/auth" \
  --jwt-type=HS256 \
  --jwt-secret=test \
  --admin-secret=admin \
  --client-id=123456 \
  --client-secret=secret
</code></pre>
<p>That's a production-ready auth server. One command. No magic.</p>
<hr />
<h2>What's in v2</h2>
<h3>13+ Database Backends</h3>
<p>Use whatever database your team already runs:</p>
<table>
<thead>
<tr>
<th>Category</th>
<th>Supported</th>
</tr>
</thead>
<tbody><tr>
<td><strong>SQL</strong></td>
<td>PostgreSQL, MySQL, SQLite, SQL Server, MariaDB, YugabyteDB, PlanetScale, CockroachDB, LibSQL</td>
</tr>
<tr>
<td><strong>NoSQL</strong></td>
<td>MongoDB, ArangoDB, CassandraDB, ScyllaDB</td>
</tr>
<tr>
<td><strong>Cloud</strong></td>
<td>AWS DynamoDB, Couchbase</td>
</tr>
</tbody></table>
<p>No other open-source auth server supports this many backends. If you're already running MongoDB or DynamoDB — you don't need to spin up a separate Postgres just for auth.</p>
<h3>11 Social Login Providers</h3>
<p>Google, GitHub, Facebook, Apple, LinkedIn, Microsoft, Discord, Twitter, Twitch, Roblox — all configured with a pair of CLI flags:</p>
<pre><code class="language-bash">--google-client-id "..." --google-client-secret "..."
--github-client-id "..." --github-client-secret "..."
</code></pre>
<h3>Multi-Factor Authentication</h3>
<ul>
<li><p><strong>TOTP</strong> — Google Authenticator, Authy, 1Password</p>
</li>
<li><p><strong>Email OTP</strong> — One-time codes via email</p>
</li>
<li><p><strong>SMS OTP</strong> — Via Twilio integration</p>
</li>
<li><p>Enforceable globally with <code>--enforce-mfa</code></p>
</li>
</ul>
<h3>Full OAuth 2.0 / OIDC Compliance</h3>
<ul>
<li><p>Authorization code flow with PKCE (RFC 7636)</p>
</li>
<li><p>Implicit token and ID token flows</p>
</li>
<li><p>JWKS endpoint (<code>/.well-known/jwks.json</code>)</p>
</li>
<li><p>9 JWT signing algorithms (HS256/384/512, RS256/384/512, ES256/384/512)</p>
</li>
<li><p>Custom access token claims via JavaScript scripts</p>
</li>
</ul>
<h3>Developer Experience</h3>
<ul>
<li><p><strong>GraphQL API</strong> — Introspectable schema, admin operations prefixed with <code>_</code></p>
</li>
<li><p><strong>REST endpoints</strong> — Standard OAuth 2.0/OIDC paths</p>
</li>
<li><p><strong>SDKs</strong> — React, JavaScript, Go, Svelte, Vue, Flutter</p>
</li>
<li><p><strong>Built-in UI</strong> — Login/signup pages out of the box, themeable</p>
</li>
<li><p><strong>Admin dashboard</strong> — User management, role assignment, email templates</p>
</li>
<li><p><strong>Webhooks</strong> — 8 event types for real-time integrations</p>
</li>
</ul>
<h3>Role-Based Access Control</h3>
<p>Define roles, set defaults, protect sensitive ones:</p>
<pre><code class="language-bash">--roles "user,admin,editor" \
--default-roles "user" \
--protected-roles "admin"
</code></pre>
<h3>One-Command Deployment</h3>
<pre><code class="language-bash"># Docker
docker run -p 8080:8080 -u root \
  -v authorizer_data:/authorizer/data \
  lakhansamani/authorizer \
  --database-type=sqlite \
  --database-url=/authorizer/data/data.db \
  --client-id=123456 \
  --client-secret=secret \
  --admin-secret=admin \
  --jwt-type=HS256 \
  --jwt-secret=test
# Or one-click deploy on Railway, Heroku, Render, Koyeb
</code></pre>
<p>Single binary. No JVM. No app server. No runtime dependencies.</p>
<hr />
<h2>What Changed From v1</h2>
<p>If you're upgrading, here's what matters:</p>
<table>
<thead>
<tr>
<th></th>
<th>v1</th>
<th>v2</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Configuration</strong></td>
<td>Stored in DB, editable via dashboard</td>
<td>CLI flags only, immutable at runtime</td>
</tr>
<tr>
<td><strong>Binary name</strong></td>
<td><code>server</code></td>
<td><code>authorizer</code></td>
</tr>
<tr>
<td><strong>Env vars</strong></td>
<td>Read from <code>.env</code> and OS</td>
<td>Pass as CLI arguments</td>
</tr>
<tr>
<td><strong>Dashboard</strong></td>
<td>Can change server config</td>
<td>Read-only (user management only)</td>
</tr>
<tr>
<td><strong>Mobile auth</strong></td>
<td>Separate <code>mobile_signup</code>/<code>mobile_login</code></td>
<td>Use <code>signup</code>/<code>login</code> with <code>phone_number</code></td>
</tr>
<tr>
<td><strong>Admin auth</strong></td>
<td>Header always enabled</td>
<td>Can disable header auth for security</td>
</tr>
<tr>
<td><strong>SDK versions</strong></td>
<td>authorizer-js v2, authorizer-react v1</td>
<td>authorizer-js v3, authorizer-react v2</td>
</tr>
</tbody></table>
<p>We wrote a detailed <a href="https://github.com/authorizerdev/authorizer/blob/main/MIGRATION.md">migration guide</a> covering every breaking change. Prefer video? Here's a <a href="https://www.youtube.com/watch?v=aQrpYCyrDjU">step-by-step migration walkthrough on YouTube</a>.</p>
<hr />
<h2>What's Coming Next: The Roadmap</h2>
<p>We're not stopping here. Here's what's planned across five phases:</p>
<h3>Phase 1: Security Hardening</h3>
<p>The foundation for enterprise adoption:</p>
<ul>
<li><p><strong>Rate limiting &amp; brute force protection</strong> — Per-IP, per-user throttling and account lockout</p>
</li>
<li><p><strong>CAPTCHA integration</strong> — Cloudflare Turnstile and Google reCAPTCHA v3</p>
</li>
<li><p><strong>Leaked password detection</strong> — Have I Been Pwned API integration</p>
</li>
<li><p><strong>Structured audit logs</strong> — Queryable event trail for compliance</p>
</li>
<li><p><strong>Prometheus metrics</strong> — <code>/metrics</code> endpoint for observability</p>
</li>
<li><p><strong>Session security</strong> — Device fingerprinting, unrecognized device alerts, remote revocation</p>
</li>
</ul>
<h3>Phase 2: Authorization &amp; Machine-to-Machine</h3>
<p>Moving beyond basic RBAC:</p>
<ul>
<li><p><strong>Fine-grained permissions</strong> — Resource-level access control (<code>document:read</code>, <code>project:admin</code>)</p>
</li>
<li><p><strong>M2M authentication</strong> — OAuth 2.0 client credentials grant for service-to-service</p>
</li>
<li><p><strong>Service accounts</strong> — Application identities that aren't tied to humans</p>
</li>
<li><p><strong>API key management</strong> — Let your users create and manage their own API keys</p>
</li>
<li><p><strong>Organization enhancements</strong> — Domain-based routing, org-level policies, invitations</p>
</li>
</ul>
<h3>Phase 3: Enterprise SSO &amp; Federation</h3>
<p>What enterprise buyers ask for on day one:</p>
<ul>
<li><p><strong>SAML 2.0</strong> — Connect to Okta, Azure AD, OneLogin</p>
</li>
<li><p><strong>SCIM 2.0 / Directory Sync</strong> — Automated user provisioning and deprovisioning</p>
</li>
<li><p><strong>Authorizer as OIDC Provider</strong> — Issue tokens for downstream services</p>
</li>
<li><p><strong>Self-service admin portal</strong> — Let customer IT teams configure their own SSO</p>
</li>
</ul>
<h3>Phase 4: AI-Era Authentication</h3>
<p>Auth is changing. AI agents need identity too:</p>
<ul>
<li><p><strong>MCP (Model Context Protocol) authorization</strong> — Secure tool access for AI agents</p>
</li>
<li><p><strong>Agent-to-Agent (A2A) authentication</strong> — Identity and delegation for autonomous agents</p>
</li>
<li><p><strong>OAuth 2.1 compliance</strong> — Mandatory PKCE, no implicit grant, refresh token rotation</p>
</li>
<li><p><strong>Token exchange (RFC 8693)</strong> — Delegation and impersonation flows</p>
</li>
<li><p><strong>Dynamic client registration (RFC 7591)</strong> — Programmatic OAuth client creation</p>
</li>
</ul>
<h3>Phase 5: Advanced Security &amp; Modern Standards</h3>
<ul>
<li><p><strong>Passkeys / WebAuthn (FIDO2)</strong> — Passwordless with hardware keys</p>
</li>
<li><p><strong>DPoP (RFC 9449)</strong> — Proof-of-possession tokens to prevent token theft</p>
</li>
<li><p><strong>Advanced bot protection</strong> — Risk scoring, credential stuffing detection</p>
</li>
<li><p><strong>SIEM integration</strong> — Stream logs to Datadog, Splunk, Elastic</p>
</li>
</ul>
<p>The full roadmap is on <a href="https://github.com/authorizerdev/authorizer/blob/main/ROADMAP_V2.md">GitHub</a>.</p>
<hr />
<h2>Why Self-Hosted Auth Matters in 2026</h2>
<p>Three trends are making self-hosted auth more relevant than ever:</p>
<p><strong>1. Data sovereignty isn't optional anymore.</strong> GDPR enforcement is accelerating. New regulations in India, Brazil, and across APAC require data residency. If your auth provider stores user data in a region you can't control, you have a compliance problem.</p>
<p><strong>2. Auth pricing doesn't scale.</strong> Hosted auth providers get expensive fast — they charge per user, per connection, or per feature. With Authorizer, you pay for a server. That's it.</p>
<p><strong>3. AI agents need auth too.</strong> MCP, A2A, and OAuth 2.1 are the emerging standards for agent authentication. The auth layer needs to evolve — and you want that evolution to happen on infrastructure you control.</p>
<hr />
<h2>Get Started</h2>
<p><strong>5-minute quickstart:</strong></p>
<pre><code class="language-bash">docker run -p 8080:8080 -u root \
  -v authorizer_data:/authorizer/data \
  lakhansamani/authorizer \
  --database-type=sqlite \
  --database-url=/authorizer/data/data.db \
  --client-id=123456 \
  --client-secret=secret \
  --admin-secret=admin \
  --jwt-type=HS256 \
  --jwt-secret=test
</code></pre>
<p>Open <code>http://localhost:8080</code> — you have a working auth server with a login page.</p>
<p><strong>Add it to your React app:</strong></p>
<pre><code class="language-bash">npm install @authorizerdev/authorizer-react
</code></pre>
<pre><code class="language-jsx">import { AuthorizerProvider, Authorizer } from '@authorizerdev/authorizer-react';

function App() {
  return (
    &lt;AuthorizerProvider
      config={{
        authorizerURL: 'http://localhost:8080',
        redirectURL: window.location.origin,
        clientID: 'my-app',
      }}
    &gt;
      &lt;Authorizer /&gt;
    &lt;/AuthorizerProvider&gt;
  );
}
</code></pre>
<p>That's email/password auth, social logins, and session management — in 15 lines.</p>
<p><strong>One-click cloud deploy:</strong></p>
<ul>
<li><p><a href="https://railway.com/deploy/nwXp1C?referralCode=FEF4uT&amp;utm_medium=integration&amp;utm_source=template&amp;utm_campaign=generic">Railway</a></p>
</li>
<li><p><a href="https://github.com/authorizerdev/authorizer-heroku">Heroku</a></p>
</li>
<li><p><a href="https://render.com/deploy?repo=https://github.com/authorizerdev/authorizer-render">Render</a></p>
</li>
</ul>
<hr />
<h2>Join the Community</h2>
<ul>
<li><p><strong>Star us on GitHub</strong>: <a href="https://github.com/authorizerdev/authorizer">github.com/authorizerdev/authorizer</a></p>
</li>
<li><p><strong>Website</strong>: <a href="https://authorizer.dev">authorizer.dev</a></p>
</li>
<li><p><strong>Read the docs</strong>: <a href="https://docs.authorizer.dev">docs.authorizer.dev</a></p>
</li>
<li><p><strong>Watch the migration video</strong>: <a href="https://www.youtube.com/watch?v=aQrpYCyrDjU">YouTube — v1 to v2 migration</a></p>
</li>
<li><p><strong>Join Discord</strong>: <a href="https://discord.gg/n7DfTjCAn">discord.gg/n7DfTjCAn</a> — Chat with the team and other developers</p>
</li>
<li><p><strong>Contribute</strong>: Check out our <a href="https://github.com/authorizerdev/authorizer/blob/main/.github/CONTRIBUTING.md">contributing guide</a></p>
</li>
</ul>
<p>Authorizer is Apache 2.0 licensed. It's free, it's open source, and your data stays yours.</p>
<p>We'd love your feedback, bug reports, and contributions. If this solves a problem for you — give us a star. It helps more than you think.</p>
<hr />
<h2>Sponsor Authorizer</h2>
<p>Authorizer is built and maintained by the community. If it saves you time or money, consider sponsoring the project to keep development going:</p>
<p><a href="https://github.com/sponsors/authorizerdev">Sponsor Authorizer on GitHub</a></p>
<hr />
<p><em>Built with Go. Powered by the community. Owned by you.</em></p>
<p><strong>About the author</strong>: I'm <a href="https://lakhan.me">Lakhan Samani</a>, creator of Authorizer. Connect with me on <a href="https://linkedin.com/in/lakhansamani">LinkedIn</a> or <a href="https://x.com/lakhansamani">X/Twitter</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Authorize NodeJS APIs using Authorizer]]></title><description><![CDATA[In this blog post, we will learn how to authorize users for API calls, based on valid sessions and roles using Authorizer. Authorizer is an open-source database-independent auth solution. You can bring your database and have authentication and author...]]></description><link>https://blog.authorizer.dev/authorize-nodejs-apis-using-authorizer</link><guid isPermaLink="true">https://blog.authorizer.dev/authorize-nodejs-apis-using-authorizer</guid><category><![CDATA[authentication]]></category><category><![CDATA[authorization]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[Docker]]></category><category><![CDATA[k8s]]></category><dc:creator><![CDATA[Lakhan Samani]]></dc:creator><pubDate>Thu, 12 Jan 2023 06:13:29 GMT</pubDate><content:encoded><![CDATA[<p>In this blog post, we will learn how to authorize users for API calls, based on valid sessions and roles using <a target="_blank" href="http://authorizer.dev/">Authorizer</a>. <a target="_blank" href="http://authorizer.dev/">Authorizer</a> is an open-source database-independent auth solution. You can bring your database and have authentication and authorization service ready out of the box.</p>
<p>For the demo purpose, we will be using [Express](<a target="_blank" href="https://expressjs.com/">https://expressjs.com/</a>) server and writing a middleware that will validate user sessions &amp; roles based on the JWT (JSON Web Token) in the <code>Authorization</code> header.</p>
<p>Refer to the source code on <a target="_blank" href="https://github.com/authorizerdev/examples/tree/main/with-express-js">github</a>.</p>
<h2 id="heading-step-1-setup-authorizer-instance">Step 1: Setup Authorizer Instance</h2>
<p>Deploy production-ready Authorizer instance using one-click deployment options available below</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Infra provider</strong></td><td><strong>One-click link</strong></td><td><strong>Additional information</strong></td></tr>
</thead>
<tbody>
<tr>
<td>Railway.app</td><td><a target="_blank" href="https://railway.app/new/template/nwXp1C?referralCode=FEF4uT">Deploy now</a></td><td><a target="_blank" href="https://docs.authorizer.dev/deployment/railway">docs</a></td></tr>
<tr>
<td>Heroku</td><td><a target="_blank" href="https://heroku.com/deploy?template=https://github.com/authorizerdev/authorizer-heroku">Deploy now</a></td><td><a target="_blank" href="https://docs.authorizer.dev/deployment/heroku">docs</a></td></tr>
<tr>
<td>Render</td><td><a target="_blank" href="https://render.com/deploy?repo=https://github.com/authorizerdev/authorizer-render">Deploy now</a></td><td><a target="_blank" href="https://docs.authorizer.dev/deployment/render">docs</a></td></tr>
</tbody>
</table>
</div><p>For more information &amp; deployment options like docker / Kubernetes / helm charts refer to the <a target="_blank" href="https://docs.authorizer.dev/deployment">docs</a></p>
<p><strong>Configure Instance</strong></p>
<ul>
<li><p>Open the Authorizer instance endpoint in a browser</p>
</li>
<li><p>SignUp as an Admin with a secure password</p>
</li>
<li><p>Configure environment variables from the dashboard. Check <a target="_blank" href="https://docs.authorizer.dev/core/env">env docs</a> for more information.</p>
<blockquote>
<p>Note: <code>DATABASE_URL</code> , <code>DATABASE_TYPE</code> , <code>REDIS_URL</code> are the variables that can only be configured as the authorizer instance's system environment variable.</p>
</blockquote>
</li>
</ul>
<h2 id="heading-step-2-create-express-app">Step 2: Create Express App</h2>
<blockquote>
<p>Note: This step is optional if you already have a Nodejs application up and running</p>
</blockquote>
<ul>
<li><p>Setup project</p>
<pre><code class="lang-bash">  <span class="hljs-comment"># Create directory</span>
  mkdir my-apis

  <span class="hljs-comment"># Change directory</span>
  <span class="hljs-built_in">cd</span> my-apis

  <span class="hljs-comment"># Initialize nodejs APP</span>
  npm init -y

  <span class="hljs-comment"># Install express</span>
  npm install express

  <span class="hljs-comment"># Create index.js</span>
  touch index.js
</code></pre>
</li>
<li><p>Add Start Command to <code>package.json</code></p>
<pre><code class="lang-javascript">  {
    <span class="hljs-string">"name"</span>: <span class="hljs-string">"my-apis"</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">"start"</span>: <span class="hljs-string">"node index.js"</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">"Lakhan Samani"</span>,
    <span class="hljs-string">"license"</span>: <span class="hljs-string">"ISC"</span>,
    <span class="hljs-string">"dependencies"</span>: {
      <span class="hljs-string">"express"</span>: <span class="hljs-string">"^4.18.2"</span>
    }
  }
</code></pre>
</li>
<li><p>Setup Express App and Create a basic API in <code>index.js</code></p>
<pre><code class="lang-javascript">  <span class="hljs-comment">// index.js</span>
  <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-string">`3000`</span>;

  app.get(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    res.send(<span class="hljs-string">'Hello World'</span>);
  });

  app.listen(port, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`[server]: Server is running at http://localhost:<span class="hljs-subst">${port}</span>`</span>);
  });
</code></pre>
</li>
</ul>
<h2 id="heading-step-3-create-authorization-middleware">Step 3: Create Authorization Middleware</h2>
<ul>
<li><p>Install <code>@authorizerdev/authorizer-js</code></p>
<pre><code class="lang-bash">  npm i --save @authorizerdev/authorizer-js
</code></pre>
</li>
<li><p>Create <code>auth_middleware.js</code></p>
<pre><code class="lang-bash">  touch auth_middleware.js
</code></pre>
</li>
<li><p>Implement authorization middleware</p>
<pre><code class="lang-javascript">  <span class="hljs-comment">// auth_middleware.js</span>

  <span class="hljs-keyword">const</span> { Authorizer } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@authorizerdev/authorizer-js"</span>);

  <span class="hljs-keyword">const</span> authRef = <span class="hljs-keyword">new</span> Authorizer({  
    <span class="hljs-attr">authorizerURL</span>: <span class="hljs-string">"AUTHORIZER_URL_FROM_STEP 1"</span>,
    <span class="hljs-attr">redirectURL</span>: <span class="hljs-string">"FRONTEND_URL"</span>,
    <span class="hljs-attr">clientID</span>: <span class="hljs-string">"AUTHORIZER_CLIENT_ID FROM DASHBOARD"</span>
  });

  <span class="hljs-keyword">const</span> authMiddleware = <span class="hljs-keyword">async</span> (req, res, next) =&gt; {
      <span class="hljs-keyword">const</span> authHeader = req.headers.authorization;
    <span class="hljs-keyword">if</span> (!authHeader) {
      <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">403</span>).json({ <span class="hljs-attr">error</span>: <span class="hljs-string">"Authorization not found"</span> });
    }

    <span class="hljs-keyword">const</span> splitHeader = authHeader.split(<span class="hljs-string">" "</span>);
    <span class="hljs-keyword">if</span> (splitHeader.length != <span class="hljs-number">2</span>) {
      <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">403</span>).json({ <span class="hljs-attr">error</span>: <span class="hljs-string">"Invalid auth header"</span> });
    }

    <span class="hljs-keyword">if</span> (splitHeader[<span class="hljs-number">0</span>].toLowerCase() != <span class="hljs-string">"bearer"</span>) {
      <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">403</span>).json({ <span class="hljs-attr">error</span>: <span class="hljs-string">"Bearer token not found"</span> });
    }

    <span class="hljs-keyword">const</span> token = splitHeader[<span class="hljs-number">1</span>];
    <span class="hljs-comment">// Validate jwt token via authorizer sdk</span>
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> authRef.validateJWTToken({
        token,
        <span class="hljs-attr">token_type</span>: <span class="hljs-string">"id_token"</span>, <span class="hljs-comment">// This can be access_token, refresh_token</span>
         <span class="hljs-comment">// roles: [user] // specify roles that you want to validate jwt for, by default it will just verify jwt.</span>
      });
      req.user = res.claims;
    } <span class="hljs-keyword">catch</span> (err) {
      <span class="hljs-built_in">console</span>.error(err);
      <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">403</span>).json({ <span class="hljs-attr">error</span>: <span class="hljs-string">"Invalid JWT token"</span> });
    }

    next();
  }

  <span class="hljs-built_in">module</span>.exports = authMiddleware
</code></pre>
</li>
</ul>
<h2 id="heading-step-4-add-auth-middleware-to-apis">Step 4: Add auth middleware to APIs</h2>
<p>Update <code>index.js</code> with following content</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// index.js</span>
<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> authMiddleware = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./auth_middleware'</span>)

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

app.get(<span class="hljs-string">'/'</span>, authMiddleware, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.send(<span class="hljs-string">'Hello World'</span>);
});

app.listen(port, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`[server]: Server is running at http://localhost:<span class="hljs-subst">${port}</span>`</span>);
});
</code></pre>
<h2 id="heading-step-5-test-the-api">Step 5: Test the API</h2>
<ul>
<li><p>Start API Server</p>
<pre><code class="lang-bash">  npm start
</code></pre>
</li>
<li><p>Make a curl request</p>
<pre><code class="lang-bash">  curl http://localhost:3000
</code></pre>
</li>
</ul>
<blockquote>
<p>Note: This will return an error, as we have not specified the Authorization header with a valid JWT token</p>
</blockquote>
<ul>
<li><p>For this test to pass we need to have a valid JWT token, so let's generate a valid JWT by making a login call to the authorizer server</p>
<pre><code class="lang-bash">  <span class="hljs-comment"># Replace Authorizer URL from step 1</span>
  <span class="hljs-comment"># Replace credentials with right credentials in --data-raw (demo@yopmail.com, Test@123#)</span>
  <span class="hljs-comment"># If you have no user on your instance, first signup using AUTHORIZER_URL_FROM_STEP_1/app?redirect_uri=AUTHORIZER_URL_FROM_STEP_1/app</span>

  curl --location --request POST <span class="hljs-string">'AUTHORIZER_URL_FROM_STEP_1/graphql'</span> \
  --header <span class="hljs-string">'Content-Type: application/json'</span> \
  --data-raw <span class="hljs-string">'{"query":"mutation login {\n  login(params: {\n    email: \"demo@yopmail.com\",\n    password: \"Test@123#\"\n  }) {\n    id_token\n  }\n}","variables":{}}'</span>
</code></pre>
<p>  This should return an <code>id_token</code> in response, as shown in the screenshot below. Copy the <code>id_token</code> from the response and pass it to our nodeJS API server</p>
</li>
<li><p>Test the API</p>
<pre><code class="lang-bash">  curl --header <span class="hljs-string">'Authorization: Bearer TOKEN_COPIED_FROM_ABOVE_STEP'</span> http://localhost:3000
</code></pre>
</li>
</ul>
<p>That's all I hope this helps you authorize your APIs easily and make them secure based on the correct session and roles.</p>
<p><strong>For more information check out the links below.</strong></p>
<ul>
<li><p>Website: <a target="_blank" href="https://authorizer.dev">https://authorizer.dev</a></p>
</li>
<li><p>Docs: <a target="_blank" href="https://docs.authorizer.dev">https://docs.authorizer.dev</a></p>
</li>
<li><p>Github: <a target="_blank" href="https://github.com/authorizerdev/authorizer">https://github.com/authorizerdev/authorizer</a></p>
</li>
<li><p>React SDK: https://github.com/authorizerdev/authorizer-react</p>
</li>
<li><p>Javascript SDK: https://github.com/authorizerdev/authorizer-js</p>
</li>
<li><p>Youtube: <a target="_blank" href="https://youtube.com/playlist?list=PLSQGbUjHc6bpaAgCiQPzNxiUPr7SkDAFR">https://youtube.com/playlist?list=PLSQGbUjHc6bpaAgCiQPzNxiUPr7SkDAFR</a></p>
</li>
<li><p>Examples: <a target="_blank" href="https://github.com/authorizerdev/examples/">https://github.com/authorizerdev/examples/</a></p>
</li>
<li><p>Discord: <a target="_blank" href="https://discord.gg/Zv2D5h6kkK">https://discord.gg/Zv2D5h6kkK</a></p>
</li>
<li><p>Github Sponsorship: https://github.com/sponsors/authorizerdev/</p>
</li>
<li><p>Buy me Coffee: <a target="_blank" href="https://www.buymeacoffee.com/lakhansamani">https://www.buymeacoffee.com/lakhansamani</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Using Authorizer with DynamoDB and EKS]]></title><description><![CDATA[Hello people, on 3rd November 2022 I had amazing opportunity to speak at AWS community (Vadodara) event happening in my city. I presented on using Authorizer with DynamoDB and EKS.
Authorizer is database independent open source auth solution. It supp...]]></description><link>https://blog.authorizer.dev/using-authorizer-with-dynamodb-and-eks</link><guid isPermaLink="true">https://blog.authorizer.dev/using-authorizer-with-dynamodb-and-eks</guid><category><![CDATA[AWS]]></category><category><![CDATA[Kubernetes]]></category><category><![CDATA[Open Source]]></category><category><![CDATA[Cloud Computing]]></category><category><![CDATA[React]]></category><dc:creator><![CDATA[Lakhan Samani]]></dc:creator><pubDate>Sat, 26 Nov 2022 05:52:44 GMT</pubDate><content:encoded><![CDATA[<p>Hello people, on 3rd November 2022 I had amazing opportunity to speak at AWS community (Vadodara) event happening in my city. I presented on using <a target="_blank" href="https://authorizer.dev">Authorizer</a> with DynamoDB and EKS.</p>
<p><a target="_blank" href="https://authorizer.dev">Authorizer</a> is database independent open source auth solution. It supports 12+ databases including all the major SQL, NoSQL and Graph databases.</p>
<p>So, as a part of demo I created a Task Manager (TODO) application, which will allow authenticated user to</p>
<ul>
<li>Create Task</li>
<li>Watch their own tasks</li>
<li>Mark Task as done</li>
<li>Delete Task</li>
</ul>
<p>The tech stack we will be using is:</p>
<ul>
<li><a target="_blank" href="https://aws.amazon.com/dynamodb/">DynamoDB</a> to store user information and tasks</li>
<li><a target="_blank" href="https://authorizer.dev">Authorizer</a> to authenticate and authorize users</li>
<li><a target="_blank" href="https://github.com/gin-gonic/gin">GoLang Gin Server</a> to create tasks apis</li>
<li><a target="_blank" href="https://reactjs.org/">React</a> to create frontend application</li>
<li><a target="_blank" href="https://aws.amazon.com/eks/">EKS</a> to deploy authorizer &amp; go-gin server</li>
<li><a target="_blank" href="https://www.netlify.com/">Netlify</a> to deploy frontend application</li>
</ul>
<p>Here is a small architecture diagram demonstrating how the overall application will look like</p>
<p><img src="https://res.cloudinary.com/dcfpom7fo/image/upload/v1668775963/Authorizer/authorizer-dynamo-eks_mq9p8g.png" alt="architecture-image" /></p>
<h2 id="heading-code-repository">Code Repository</h2>
<p><a target="_blank" href="https://github.com/lakhansamani/authorizer-aws-demo">Github Repository</a>: This repository contains code for <a target="_blank" href="https://github.com/lakhansamani/authorizer-aws-demo/tree/main/apis">TODO API</a>, <a target="_blank" href="https://github.com/lakhansamani/authorizer-aws-demo/tree/main/todo-app">Frontend Application</a>, <a target="_blank" href="https://github.com/lakhansamani/authorizer-aws-demo/blob/main/eks.yaml">EKS Cluster Creation</a>, <a target="_blank" href="https://github.com/lakhansamani/authorizer-aws-demo/blob/main/authorizer_ingress.yaml">Ingress / Domain Setup</a></p>
<h2 id="heading-lets-get-started">Let's Get Started</h2>
<h3 id="heading-prerequisite">Prerequisite</h3>
<ul>
<li><a target="_blank" href="https://aws.amazon.com/">aws account</a></li>
<li><a target="_blank" href="https://aws.amazon.com/iam/">iam</a> user with permission for DynamoDB, EKS, EC2, IAM Policy Creation, Route53, EBS Controller</li>
<li><a target="_blank" href="https://kubernetes.io/docs/tasks/tools/">kubectl</a></li>
<li><a target="_blank" href="https://aws.amazon.com/cli/">awscli</a></li>
<li><a target="_blank" href="https://eksctl.io/">eksctl</a></li>
<li><a target="_blank" href="https://helm.sh/">helm</a></li>
<li>Configure AWS profile on your machine with user credentials</li>
<li>Export your AWS credentials<pre><code class="lang-sh">aws configure --profile PROFILE_NAME
<span class="hljs-built_in">export</span> AWS_PROFILE=PROFILE_NAME
<span class="hljs-built_in">export</span> AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEY_ID
<span class="hljs-built_in">export</span> AWS_SECRET_ACCESS_KEY=YOUR_SECRET_ACCESS_KEY
</code></pre>
</li>
</ul>
<h3 id="heading-step-1-clone-the-repository">Step 1: Clone the Repository</h3>
<pre><code class="lang-sh">git <span class="hljs-built_in">clone</span> https://github.com/lakhansamani/authorizer-aws-demo.git

<span class="hljs-built_in">cd</span> authorizer-aws-demo
</code></pre>
<h3 id="heading-step-2-create-eks-cluster">Step 2: Create EKS Cluster</h3>
<blockquote>
<p>Note: You can update machine configuration in eks.yaml file.</p>
</blockquote>
<pre><code class="lang-sh">eksctl create cluster -f eks.yaml
</code></pre>
<h3 id="heading-step-3-install-nginx-ingress">Step 3: Install Nginx Ingress</h3>
<pre><code class="lang-sh">helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx

helm repo update

helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx \
 --namespace ingress-nginx \
 --create-namespace \
 --timeout 600s \
 --debug \
 --<span class="hljs-built_in">set</span> controller.publishService.enabled=<span class="hljs-literal">true</span>
</code></pre>
<h3 id="heading-step-4-install-cert-manager">Step 4: Install Cert Manager</h3>
<p>Cert manager is used to generate TLS certificate</p>
<pre><code class="lang-sh">helm repo add jetstack https://charts.jetstack.io

helm repo update

kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.8.2/cert-manager.crds.yaml

helm install \
 cert-manager jetstack/cert-manager \
 --namespace cert-manager \
 --create-namespace \
 --version v1.8.2
</code></pre>
<h3 id="heading-step-5-install-authorizer">Step 5: Install Authorizer</h3>
<blockquote>
<p>Note: Please change <code>authorizer.authorizer_url</code> as per your domain and URL.</p>
</blockquote>
<pre><code class="lang-sh">helm repo add authorizer https://helm-charts.authorizer.dev

helm repo update

helm install \
 --<span class="hljs-built_in">set</span> authorizer.database_type=dynamodb \
 --<span class="hljs-built_in">set</span> authorizer.aws_access_key_id=<span class="hljs-variable">${AWS_ACCESS_KEY_ID}</span> \
 --<span class="hljs-built_in">set</span> authorizer.aws_secret_access_key=<span class="hljs-variable">${AWS_SECRET_ACCESS_KEY}</span> \
 --<span class="hljs-built_in">set</span> authorizer.aws_region=us-east-1 \
 --<span class="hljs-built_in">set</span> authorizer.authorizer_url=https://auth.aws-demo.authorizer.dev \
 --<span class="hljs-built_in">set</span> redis.install=<span class="hljs-literal">true</span> \
 --<span class="hljs-built_in">set</span> redis.storage=5Gi \
 --<span class="hljs-built_in">set</span> redis.storageClassName=gp2 \
 --<span class="hljs-built_in">set</span> securityContext.readOnlyRootFilesystem=<span class="hljs-literal">false</span> \
authorizer authorizer/authorizer
</code></pre>
<h3 id="heading-step-6-create-route53-hosted-zone">Step 6: Create Route53 Hosted Zone</h3>
<ul>
<li>Create Hosted Zone</li>
<li>Create Subdomain Record with classic load balancer and select loadbalancer created by nginx</li>
</ul>
<p>Example: <code>auth.aws-demo.authorizer.dev</code> in below screenshot</p>
<p><img src="https://res.cloudinary.com/dcfpom7fo/image/upload/v1668775970/Authorizer/aws-route-53_jzijgx.png" alt="route53" /></p>
<h3 id="heading-step-7-create-cluster-issuer-with-dns01-challenge">Step 7: Create Cluster Issuer with dns01 challenge</h3>
<blockquote>
<p>Note: Change email &amp; hostzoneID as per step5 in <code>cluster_issuer.yaml</code></p>
</blockquote>
<p>Cert manager will add txt record and will verify the domain details using this issuer.</p>
<pre><code class="lang-sh">kubectl apply -f cluster_issuer.yaml
</code></pre>
<h3 id="heading-step-8-create-ingress-for-authorizer">Step 8: Create Ingress for authorizer</h3>
<blockquote>
<p>Note: Change authorizer domain as per your auth domain in <code>authorizer_ingress.yaml</code></p>
</blockquote>
<pre><code class="lang-sh">kubectl apply -f authorizer_ingress.yaml
</code></pre>
<p>Open your authorizer dashboard, configure admin password and get client ID.</p>
<h3 id="heading-step-9-deploy-api-resources">Step 9: Deploy API resources</h3>
<blockquote>
<p>Note: Change <code>authorizer_client_id</code> to based64 encoded value authorizer client_id value obtained in step 7 in api.yaml L:8. Also change domain name in ingress section.</p>
</blockquote>
<pre><code class="lang-sh">kubectl apply -f api.yaml
</code></pre>
<h3 id="heading-step-10-deploy-frontend">Step 10: Deploy frontend</h3>
<p>You can deploy frontend to provider of your choice OR on the same stack. For demo purpose I have deployed it on Netlify and connected subdomain there.</p>
<p>Thats all you need. Hope it makes your life easier to deploy authorizer + any other service on AWS</p>
<p><strong>For more information check</strong></p>
<ul>
<li>Website: https://authorizer.dev</li>
<li>Docs: https://docs.authorizer.dev</li>
<li>Github: https://github.com/authorizerdev/authorizer</li>
<li>React-SDK: https://github.com/authorizerdev/authorizer-react</li>
<li>JS-SDK: https://github.com/authorizerdev/authorizer-js</li>
<li>Youtube: https://youtube.com/playlist?list=PLSQGbUjHc6bpaAgCiQPzNxiUPr7SkDAFR</li>
<li>Discord: https://discord.gg/Zv2D5h6kkK</li>
<li>Github Sponsorship: https://github.com/sponsors/authorizerdev</li>
<li>Buy me coffee: https://www.buymeacoffee.com/lakhansamani</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Introducing Authorizer 1.0]]></title><description><![CDATA[We’re excited to announce the stable version of https://authorizer.dev with the most significant updates 🥳. The most complex part of your application, i.e. auth has never been this simple in the open-source space before. Bring your database and have...]]></description><link>https://blog.authorizer.dev/introducing-authorizer-10</link><guid isPermaLink="true">https://blog.authorizer.dev/introducing-authorizer-10</guid><category><![CDATA[authorization]]></category><category><![CDATA[authentication]]></category><category><![CDATA[Open Source]]></category><category><![CDATA[React]]></category><category><![CDATA[golang]]></category><dc:creator><![CDATA[Lakhan Samani]]></dc:creator><pubDate>Mon, 15 Aug 2022 16:39:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1660581329108/cmdFouwiq.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>We’re excited to announce the stable version of <a target="_blank" href="https://authorizer.dev">https://authorizer.dev</a> with the most significant updates 🥳. The most complex part of your application, i.e. auth has never been this simple in the open-source space before. Bring your database and have auth layer ready for the application within minutes 🚀.</p>
<h2 id="heading-you-can-get-started-in-3-easy-steps">You can get started in 3 easy steps</h2>
<p><strong>Step 1:</strong> <a target="_blank" href="https://docs.authorizer.dev/getting-started">Deploy Authorizer Instance</a></p>
<p><strong>Step 2:</strong> <a target="_blank" href="https://docs.authorizer.dev/getting-started">Setup the instance using built-in dashboard</a></p>
<p><strong>Step 3</strong>: <a target="_blank" href="https://docs.authorizer.dev/getting-started">Integrate the universal login page with your application</a></p>
<p>Let’s have a look at the amazing set of features 🚀</p>
<h2 id="heading-secure-session-management">Secure Session Management</h2>
<p>Authorizer follows the best practices in the auth space and gives you secure session management using</p>
<ul>
<li>HTTP only cookies (Recommended for web)</li>
<li><a target="_blank" href="https://oauth.net/2/pkce/">Authorization Code Flow</a> (Recommended for mobile applications)</li>
<li>OAuth2 with Open ID compatible APIs</li>
</ul>
<h2 id="heading-multiple-auth-recipes">Multiple Auth Recipes</h2>
<p>Authorizer comes with an amazing set of auth recipes out of the box, which includes major social media logins, magic link login, and basic authentication. You can easily configure this recipe using the dashboard that is shipped with every instance of Authorizer. </p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zi8ls2q0xh29wqnnxgwf.png" alt="Image description" /></p>
<h2 id="heading-myriad-database-support">Myriad Database Support</h2>
<p>Authorizer now supports 11+ databases including major SQL, NoSQL, and GraphDB with the motive <strong>Your Data Your Control</strong>. Bring your database and it will just add a few tables/collections in your database to generate auth layer for you.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c9vm24aswwxy3r5cmn73.png" alt="Image description" /></p>
<h2 id="heading-role-base-access-control">Role Base Access Control</h2>
<p>Secure your APIs and UI depending on various roles for your application. You can easily configure the user roles in your dashboard and have them validated in the JWT tokens.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/49fk0xg147mvyls0v1uv.png" alt="Image description" /> </p>
<h2 id="heading-integrate-implement">Integrate / Implement</h2>
<p>Every instance of Authorizer comes with a universal login page which you can integrate in your application with a few lines of code. This page is rendered based on the configuration you have in the dashboard. Still, if you need to build the custom UI then we have React SDK and JS SDK which you can leverage.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1fr5m7ktmz3z5qqs2uxd.png" alt="Image description" /></p>
<h2 id="heading-custom-emails">Custom Emails</h2>
<p>Now you can send emails for various Authorizer events with your own design and messaging. You can also give personal touch to this emails with the help of dynamic variables that will be replaced before sending emails</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qlaao08mvfita7buoy56.png" alt="Image description" /> </p>
<h2 id="heading-multi-factor-authentication">Multi-factor Authentication</h2>
<p>Now you can add one more layer of security by enabling multi-factor authentication which will send one time passwords (OTP) via emails to users and after entering that password only user will be able to access your application. This feature is enabled for basic authentication at the moment.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8vrifkrm2tykiwsi58gx.png" alt="Image description" /> </p>
<h2 id="heading-listen-to-events">Listen to events</h2>
<p>Most advanced feature of Authorizer. You can now listen to various Authorizer events in your APIs with the help of webhooks and take further actions if required</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4snaxte5vzw52mywz1c9.png" alt="Image description" /> </p>
<p>With all this amazing set of features, you can deploy Authorizer instances on your infrastructure using Docker, Kubernetes, or Binaries. Also, you can use the one-click deployment options that we offer to get started quickly 🚀</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/DFgo0TuA4c8">https://youtu.be/DFgo0TuA4c8</a></div>
<p>I hope you like it and give it a try. You can support our work by contributing to the project, sending Github sponsorship, buying us coffee, or giving us a star on Github. For more information check out the links below.</p>
<p>Website: <a target="_blank" href="https://authorizer.dev">https://authorizer.dev</a> </p>
<p>Docs: <a target="_blank" href="https://docs.authorizer.dev">https://docs.authorizer.dev</a> </p>
<p>Github: <a target="_blank" href="https://github.com/authorizerdev/authorizer">https://github.com/authorizerdev/authorizer</a> </p>
<p>React SDK: https://github.com/authorizerdev/authorizer-react</p>
<p>Javascript SDK: https://github.com/authorizerdev/authorizer-js</p>
<p>Youtube: <a target="_blank" href="https://youtube.com/playlist?list=PLSQGbUjHc6bpaAgCiQPzNxiUPr7SkDAFR">https://youtube.com/playlist?list=PLSQGbUjHc6bpaAgCiQPzNxiUPr7SkDAFR</a> </p>
<p>Examples: <a target="_blank" href="https://github.com/authorizerdev/examples/">https://github.com/authorizerdev/examples/</a></p>
<p>Discord: <a target="_blank" href="https://discord.gg/Zv2D5h6kkK">https://discord.gg/Zv2D5h6kkK</a></p>
<p>Github Sponsorship: https://github.com/sponsors/authorizerdev/</p>
<p>Buy me Coffee: <a target="_blank" href="https://www.buymeacoffee.com/lakhansamani">https://www.buymeacoffee.com/lakhansamani</a></p>
]]></content:encoded></item></channel></rss>