<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Stefano Pinato</title>
    <description>The latest articles on DEV Community by Stefano Pinato (@_stefano_pinato).</description>
    <link>https://dev.to/_stefano_pinato</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4022944%2F894e64a7-845d-439a-85a6-39ca74159552.jpg</url>
      <title>DEV Community: Stefano Pinato</title>
      <link>https://dev.to/_stefano_pinato</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/_stefano_pinato"/>
    <language>en</language>
    <item>
      <title>OpenIddict and IdentitySuite — secure configuration without the complexity</title>
      <dc:creator>Stefano Pinato</dc:creator>
      <pubDate>Mon, 27 Jul 2026 18:13:50 +0000</pubDate>
      <link>https://dev.to/_stefano_pinato/openiddict-and-identitysuite-secure-configuration-without-the-complexity-17jh</link>
      <guid>https://dev.to/_stefano_pinato/openiddict-and-identitysuite-secure-configuration-without-the-complexity-17jh</guid>
      <description>&lt;p&gt;Closing out the series — &lt;a href="https://dev.to/_stefano_pinato/what-is-openiddict-the-net-framework-developers-choose-for-oauth-20-and-openid-connect"&gt;part 1&lt;/a&gt; covered what OpenIddict is, &lt;a href="https://dev.to/_stefano_pinato/the-pitfalls-of-configuring-openiddict-from-scratch-what-can-go-wrong"&gt;part 2&lt;/a&gt; covered what commonly goes wrong. This time: how I ended up solving each of those pitfalls in IdentitySuite, the identity server I've been building on top of OpenIddict.&lt;/p&gt;

&lt;h2&gt;
  
  
  Secure configuration without the complexity
&lt;/h2&gt;

&lt;p&gt;In the previous article, we looked at the most common mistakes developers make when configuring OpenIddict from scratch — development certificates in production, token lifetimes left at defaults, missing PKCE enforcement, loose redirect URI validation, and no revocation strategy. Each one is a real vulnerability, not just a best practice to follow when convenient.&lt;/p&gt;

&lt;p&gt;In this article, I'll go through how IdentitySuite addresses each of those points — and in most cases, that answer requires no code at all.&lt;/p&gt;

&lt;h3&gt;
  
  
  Certificates — persistent, managed, monitored
&lt;/h3&gt;

&lt;p&gt;The pitfall: development certificates are ephemeral. Every restart invalidates all active tokens, and they are not suitable for production under any circumstances.&lt;/p&gt;

&lt;p&gt;IdentitySuite handles certificate management as a first-class concern, with two distinct modes depending on your deployment requirements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Built-in certificates&lt;/strong&gt; are the default mode. IdentitySuite generates RSA 4096 self-signed certificates automatically and manages their entire lifecycle — creation, storage, and rotation — without any manual intervention. When a certificate approaches expiry, the system rotates it automatically and keeps the previous certificate available for long enough to cover all tokens that were issued with it. No expired token is invalidated prematurely.&lt;/p&gt;

&lt;p&gt;While self-signed certificates are not the recommended choice for high-compliance environments, they are a legitimate option for production — RSA 4096 provides strong cryptographic guarantees, and the fully automated lifecycle removes the operational risk of forgetting a manual rotation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Custom certificates&lt;/strong&gt; allow you to load your own certificates — from the filesystem or from the certificate store on systems that support it. This is the recommended path when your security policy requires certificates issued by a trusted CA or managed through your organization's PKI. In this mode, rotation is manual: you upload the new certificate when needed, and IdentitySuite handles the transition, keeping the previous certificate active until all tokens signed with it have expired.&lt;/p&gt;

&lt;p&gt;In both modes, the Dashboard displays the expiry status of signing and encryption certificates in real time, with visual warnings when rotation is approaching. No scripts to write, no external monitoring to set up — the system surfaces the information where it is needed.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;What this means in practice&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Certificates survive application restarts and are consistent across all instances of your deployment. In a load-balanced environment, every node uses the same certificate — tokens issued by one instance are valid on all others. And regardless of the rotation mode, no active token is ever invalidated early due to a certificate change.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Token lifetimes — explicit, configurable, visible
&lt;/h3&gt;

&lt;p&gt;The pitfall: leaving token lifetimes at framework defaults means access tokens that are valid far longer than necessary, with no easy way to adjust them without touching code.&lt;/p&gt;

&lt;p&gt;In IdentitySuite, every token lifetime is configurable from the admin UI. Access tokens, refresh tokens, authorization codes, identity tokens, device codes — each has its own field, with the current value always visible.&lt;/p&gt;

&lt;p&gt;The defaults IdentitySuite ships with are deliberately conservative — short access token lifetimes, reasonable refresh token windows. You can adjust them at any time without a redeployment. Since token lifetimes are read at startup, changes take effect after the next process recycle — which in most hosting environments means a few seconds.&lt;/p&gt;

&lt;h3&gt;
  
  
  PKCE — enforced at the server level
&lt;/h3&gt;

&lt;p&gt;The pitfall: OpenIddict supports PKCE but does not enforce it by default. A single missing method call leaves public clients vulnerable to authorization code interception.&lt;/p&gt;

&lt;p&gt;IdentitySuite enforces PKCE at the server level for all authorization code flows by default — the configuration is applied globally and consistently, regardless of how individual clients are registered. For most deployments, this is the right choice and requires no additional setup.&lt;/p&gt;

&lt;p&gt;If your scenario requires more flexibility — for example, when integrating legacy clients that do not support PKCE — the enforcement can be disabled through a configuration option. The default, however, is always the secure one: PKCE on, protection active from the first request.&lt;/p&gt;

&lt;p&gt;The same requirement is visible and verifiable at the individual client level, so you always know exactly what security constraints apply to each registered application — without having to cross-reference multiple configuration files.&lt;/p&gt;

&lt;h3&gt;
  
  
  Redirect URIs — exact matching, no exceptions
&lt;/h3&gt;

&lt;p&gt;The pitfall: registering redirect URIs that are too broad, or accepting wildcards and pattern matching, creates open redirect vulnerabilities that can be exploited to capture authorization codes.&lt;/p&gt;

&lt;p&gt;In IdentitySuite, redirect URIs are registered per client through the admin interface. The validation model enforces exact URI matching — what you register is exactly what will be accepted, nothing more. There are no wildcards, no path prefixes, no pattern matching.&lt;/p&gt;

&lt;p&gt;Adding or removing redirect URIs requires no code changes and no redeployment. Client configurations are stored in the database and take effect immediately, which is particularly useful during onboarding of new client applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scopes and audiences — consistent by design
&lt;/h3&gt;

&lt;p&gt;The pitfall: in a raw OpenIddict setup, scopes and audiences must be configured consistently across three separate places — the server registration, the API resource definitions, and each client registration. A mismatch at any point produces tokens that either fail validation or grant access they should not.&lt;/p&gt;

&lt;p&gt;IdentitySuite structures this as a clear hierarchy. At the server level, you define which scopes are globally available. Each API scope is then associated with one or more API resources — the actual services that will validate tokens. Finally, each client declares exactly which identity scopes and API scopes it is allowed to request.&lt;/p&gt;

&lt;p&gt;Because every level references the one above it, the configuration is always coherent end-to-end. There is no way to assign a scope to a client that has not been defined at the server level, and no way for a token to reach an API resource it was not intended for.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Why this matters&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Scope and audience misconfiguration is one of the most common sources of frustration when setting up an authorization server from scratch. IdentitySuite resolves it structurally — the hierarchy enforces consistency, so there is no configuration to get wrong.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Token revocation — available when you need it most
&lt;/h3&gt;

&lt;p&gt;The pitfall: skipping token revocation means that in the event of a security incident, compromised tokens remain valid until they naturally expire — with no way to stop them.&lt;/p&gt;

&lt;p&gt;IdentitySuite includes a token revocation system built directly into the Dashboard. A single action revokes all active tokens across all clients — useful in emergency scenarios such as a suspected credential leak or a Data Protection key rotation.&lt;/p&gt;

&lt;p&gt;Per-client revocation is also available, allowing you to terminate all sessions for a specific application without affecting others. Both actions are audited, so there is always a record of when revocation happened and who triggered it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Emergency revocation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you revoke all tokens alongside a Data Protection key rotation, IdentitySuite handles the post-revocation session cleanup automatically — including the antiforgery cookie invalidation that would otherwise leave the admin UI in a broken state.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  What you actually write
&lt;/h3&gt;

&lt;p&gt;To put this in perspective: getting OpenIddict to a production-ready state from scratch requires writing and maintaining a significant amount of security-critical configuration code. Certificates, lifetimes, PKCE enforcement, redirect URI validation, scope definitions, revocation endpoints — each one is a decision point where a mistake has consequences.&lt;/p&gt;

&lt;p&gt;With IdentitySuite, your &lt;code&gt;Program.cs&lt;/code&gt; looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddIdentitySuiteServices&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetupIdentitySuiteDbAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseIdentitySuiteServices&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything covered in this series — certificates, token lifetimes, PKCE, redirect URIs, scopes, audiences, revocation — is handled internally by those three method calls. The design philosophy is deliberate: ship with secure, production-ready defaults so you can get a working, secure environment up and running immediately, without writing a single line of security-critical code.&lt;/p&gt;

&lt;p&gt;At the same time, the system remains highly configurable. All the settings discussed in this article are manageable through the admin UI at runtime — no code changes, no configuration file edits required. For teams that need deeper customization, a full set of options is available to tailor every aspect of the system to their specific requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up the series
&lt;/h2&gt;

&lt;p&gt;Over three articles, we've covered what OpenIddict is, where its configuration complexity lies, and how IdentitySuite addresses each of those points in a structured and auditable way.&lt;/p&gt;

&lt;p&gt;If you're building a .NET application that needs OAuth 2.0 or OpenID Connect, and you want the reliability of OpenIddict without the configuration surface, &lt;a href="https://identitysuite.net" rel="noopener noreferrer"&gt;IdentitySuite&lt;/a&gt; is worth a look. It's free to run forever for small deployments (1 client / 100 users), with paid plans for larger setups.&lt;/p&gt;

&lt;p&gt;Happy to answer questions about any of the decisions covered in this series, OpenIddict in general, or IdentitySuite specifically.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>aspnetcore</category>
      <category>security</category>
    </item>
    <item>
      <title>The pitfalls of configuring OpenIddict from scratch — what can go wrong</title>
      <dc:creator>Stefano Pinato</dc:creator>
      <pubDate>Wed, 22 Jul 2026 21:21:09 +0000</pubDate>
      <link>https://dev.to/_stefano_pinato/the-pitfalls-of-configuring-openiddict-from-scratch-what-can-go-wrong-11d5</link>
      <guid>https://dev.to/_stefano_pinato/the-pitfalls-of-configuring-openiddict-from-scratch-what-can-go-wrong-11d5</guid>
      <description>&lt;p&gt;Part 2 of the series — in &lt;a href="https://dev.to/_stefano_pinato/what-is-openiddict-the-net-framework-developers-choose-for-oauth-20-and-openid-connect"&gt;part 1&lt;/a&gt; we covered what OpenIddict is. This time: what goes wrong when configuring it, and why.&lt;/p&gt;

&lt;h2&gt;
  
  
  What can go wrong — and why it matters more than you think
&lt;/h2&gt;

&lt;p&gt;In the previous article, we established what OpenIddict is and why it has become the go-to choice for .NET developers who need a standards-compliant authorization server. The framework is solid, well-maintained, and flexible.&lt;/p&gt;

&lt;p&gt;That flexibility, however, comes at a cost. OpenIddict does not make decisions for you — it gives you the tools and expects you to use them correctly. And in the security domain, &lt;strong&gt;incorrect configuration is not just a bug: it is a vulnerability&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This article covers the most common mistakes developers make when setting up OpenIddict from scratch, and what the actual consequences are when those mistakes reach production.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using development certificates in production
&lt;/h3&gt;

&lt;p&gt;OpenIddict makes it very easy to get started locally. Two method calls and you have working signing and encryption certificates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddDevelopmentEncryptionCertificate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddDevelopmentSigningCertificate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These methods generate ephemeral certificates that live only in memory. Every time the application restarts, new certificates are generated — which means every token signed before the restart becomes invalid immediately. Users get logged out, API calls start failing, and refresh tokens stop working.&lt;/p&gt;

&lt;p&gt;More critically, development certificates are not suitable for production from a security standpoint. They offer no guarantee of key strength, no rotation policy, and no audit trail. They exist purely to reduce friction during development.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Real-world consequence&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Development certificates in production means every application restart invalidates all active sessions. In a load-balanced environment with multiple instances, tokens signed by one instance cannot be validated by another. The result is constant, unpredictable authentication failures.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The correct approach is to provide persistent certificates — loaded from the filesystem or the Windows certificate store — that survive restarts and are shared across all instances of your application. This requires understanding certificate formats, key storage, and rotation strategies before you write a single line of configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Token lifetimes that are too long — or not set at all
&lt;/h3&gt;

&lt;p&gt;OpenIddict allows you to configure the lifetime of every token type: access tokens, refresh tokens, authorization codes, identity tokens. If you do not set these explicitly, the defaults apply — and while the defaults are reasonable, they may not be appropriate for your threat model.&lt;/p&gt;

&lt;p&gt;The problem developers run into most often is access tokens with lifetimes that are far too long. An access token that is valid for 24 hours gives an attacker a 24-hour window to use a stolen token without any way to invalidate it, unless you have also set up token introspection or reference tokens.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Setting explicit lifetimes is not optional in production&lt;/span&gt;
&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetAccessTokenLifetime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromMinutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;15&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetRefreshTokenLifetime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromDays&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;14&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetAuthorizationCodeLifetime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromMinutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Short access token lifetimes force clients to refresh frequently, which gives you more opportunities to detect and revoke compromised sessions. Authorization codes should be especially short-lived — they are single-use credentials that should expire in seconds, not minutes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;The balance to find&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Very short lifetimes improve security but increase the frequency of token refresh operations, which adds load to your server and latency for your users. There is no universal answer — the right values depend on your application's sensitivity and usage patterns.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Not enforcing PKCE for public clients
&lt;/h3&gt;

&lt;p&gt;PKCE (Proof Key for Code Exchange) is a mechanism that prevents authorization code interception attacks. It is mandatory for public clients — browser-based applications and mobile apps that cannot securely store a client secret.&lt;/p&gt;

&lt;p&gt;OpenIddict supports PKCE, but it does not enforce it by default for every client. If you register a public client without requiring PKCE, that client can complete an authorization code flow without it. An attacker who intercepts the authorization code — through a malicious redirect, a browser extension, or a misconfigured redirect URI — can exchange it for tokens directly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// This enables PKCE support but does not enforce it&lt;/span&gt;
&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AllowAuthorizationCodeFlow&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// This makes PKCE mandatory for all authorization code requests&lt;/span&gt;
&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AllowAuthorizationCodeFlow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RequireProofKeyForCodeExchange&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difference between these two lines is small in code but significant in practice. Per-client enforcement requires additional configuration at the client registration level, which adds another surface for misconfiguration if not handled carefully.&lt;/p&gt;

&lt;h3&gt;
  
  
  Loose redirect URI validation
&lt;/h3&gt;

&lt;p&gt;Redirect URIs are one of the most critical security boundaries in OAuth 2.0. After a user authenticates, the authorization server sends the authorization code to the redirect URI registered for that client. If an attacker can influence where that code is sent, they can capture it.&lt;/p&gt;

&lt;p&gt;OpenIddict performs redirect URI validation, but the quality of that validation depends entirely on how you register your clients. Common mistakes include registering URIs that are too broad, allowing trailing wildcards, or accepting &lt;code&gt;localhost&lt;/code&gt; URIs in production configurations.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;What a misconfigured redirect URI looks like&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Registering &lt;code&gt;https://app.example.com/&lt;/code&gt; as a redirect URI and then accepting any path under that origin is an open redirect vulnerability. An attacker crafts a link that redirects the authorization code to a path they control under your domain. The fix is always exact URI matching — no wildcards, no pattern matching, no exceptions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Scope and audience misconfiguration
&lt;/h3&gt;

&lt;p&gt;Scopes and audiences define what a token is valid for. A token issued with the wrong audience will be accepted by resource servers it was never intended to reach. A token with overly broad scopes gives the bearer more access than they should have.&lt;/p&gt;

&lt;p&gt;Getting this right requires understanding the relationship between client registrations, scope definitions, and resource server validation — three separate concepts that need to be configured consistently. A mismatch at any point in the chain produces tokens that either do not work at all or work in ways you did not intend.&lt;/p&gt;

&lt;h3&gt;
  
  
  Skipping token revocation
&lt;/h3&gt;

&lt;p&gt;By default, JWT access tokens are self-contained and stateless. Once issued, they are valid until they expire — there is no built-in mechanism to invalidate them early. This is fine for short-lived tokens, but becomes a problem when you need to respond to a security incident, a user logs out, or an account is compromised.&lt;/p&gt;

&lt;p&gt;OpenIddict supports reference tokens, which store the actual token payload in the database and issue only an opaque handle to the client. This makes revocation straightforward — you delete the record and the token stops working immediately. But reference tokens require token introspection at every API call, which adds a database lookup to each request.&lt;/p&gt;

&lt;p&gt;Choosing between JWT and reference tokens — and setting up revocation correctly for either — is a decision that has to be made deliberately, based on your application's requirements. Skipping it because it seems complex is a common shortcut with real consequences.&lt;/p&gt;

&lt;h3&gt;
  
  
  The underlying pattern
&lt;/h3&gt;

&lt;p&gt;Looking at these pitfalls together, a pattern emerges: none of them are caused by bugs in OpenIddict. They are all the result of decisions — or the absence of decisions — during configuration. OpenIddict is a general-purpose framework, and general-purpose frameworks cannot make security decisions on your behalf.&lt;/p&gt;

&lt;p&gt;This is not a criticism of the library. It is simply the nature of building something flexible enough to serve a wide range of use cases. The trade-off is that every team using OpenIddict needs to develop enough expertise to configure it correctly — or rely on something that has already made those decisions in a secure and consistent way.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>aspnetcore</category>
      <category>security</category>
    </item>
    <item>
      <title>Introducing IdentitySuite 3.0</title>
      <dc:creator>Stefano Pinato</dc:creator>
      <pubDate>Tue, 14 Jul 2026 09:43:00 +0000</pubDate>
      <link>https://dev.to/_stefano_pinato/introducing-identitysuite-30-ncl</link>
      <guid>https://dev.to/_stefano_pinato/introducing-identitysuite-30-ncl</guid>
      <description>&lt;p&gt;I've been writing a short series on OpenIddict basics while preparing this release — IdentitySuite 3.0 is our biggest visual and customization update yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's New in IdentitySuite 3.0
&lt;/h2&gt;

&lt;p&gt;IdentitySuite 3.0 is our most visually ambitious release yet. We've reimagined how developers and designers customize authentication and account management pages, introducing a modern Theme Builder with new templates, gradient support, image backgrounds, and a centralized image library shared across each client.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🚀 &lt;strong&gt;Highlight&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;New Theme Builder with 4 templates&lt;/li&gt;
&lt;li&gt;Gradient and image backgrounds&lt;/li&gt;
&lt;li&gt;Centralized Image Library per client&lt;/li&gt;
&lt;li&gt;New social login providers: GitHub, Apple, LinkedIn, Instagram&lt;/li&gt;
&lt;li&gt;Live preview with desktop/mobile emulation&lt;/li&gt;
&lt;li&gt;Automatic section highlighting while editing&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  1. A Completely Redesigned Theme Builder
&lt;/h3&gt;

&lt;p&gt;The new Theme Builder introduces a more intuitive and powerful way to customize every visual aspect of your authentication and account management pages. With four new templates and dozens of configurable properties, IdentitySuite 3.0 gives you full control over layout, spacing, typography, backgrounds, and branding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Four New Layout Templates&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Centered Form&lt;/strong&gt; — Classic layout with the form centered and the logo above.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Form Left&lt;/strong&gt; — Form on the right, brand panel on the left.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Form Right&lt;/strong&gt; — Form on the left, brand panel on the right.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Centered Layout&lt;/strong&gt; — Logo and title above the form, subtitle below.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each template unlocks different customization options inside the Theme Builder, such as Page Container, Brand Panel, Card Header, and Card Body.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gradient &amp;amp; Image Backgrounds&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Version 3.0 introduces full support for gradient backgrounds and image backgrounds across multiple sections, including Page, Page Container, Brand Panel, and Card Body. This allows you to create visually rich and modern layouts with minimal effort.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Live Preview with Automatic Highlighting&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The preview area now includes desktop and mobile emulation, and automatically highlights the section you are editing with a red outline. This makes it easier to understand exactly which part of the page is being modified.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Pro Tip — Default Values&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Default Values accordion allows you to define global parameters such as background, color, border-radius, border-width, and typography. When you click Apply, these values are automatically propagated to all compatible elements, instantly updating the entire theme preview. You can then refine individual components using their specific settings for precise visual control.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2. New Social Login Providers
&lt;/h3&gt;

&lt;p&gt;IdentitySuite 3.0 expands its authentication capabilities with four new social login providers: &lt;strong&gt;GitHub&lt;/strong&gt;, &lt;strong&gt;Apple&lt;/strong&gt;, &lt;strong&gt;LinkedIn&lt;/strong&gt;, and &lt;strong&gt;Instagram&lt;/strong&gt;. Combined with the existing Google, Facebook, and Microsoft providers, this update offers more flexibility and a smoother onboarding experience for end users.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Centralized Image Library
&lt;/h3&gt;

&lt;p&gt;Each client now includes a centralized Image Library used for logos, background images, and brand assets. Images can be uploaded, reused, or removed directly from the Appearance panel or the Email Builder, ensuring consistent branding across all pages and email templates.&lt;/p&gt;

&lt;p&gt;The Theme Builder integrates seamlessly with the Image Library, allowing you to select logos and background images while customizing the Brand Panel or Page Container.&lt;/p&gt;

&lt;p&gt;For a complete overview of the new Theme Builder, including templates, layout controls, gradient backgrounds, and image management, check out the &lt;a href="https://identitysuite.net/documentation/ThemeBuilder" rel="noopener noreferrer"&gt;Theme Builder documentation&lt;/a&gt;, and browse real examples in the new &lt;a href="https://identitysuite.net/identity-gallery" rel="noopener noreferrer"&gt;IdentitySuite UI Gallery&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Improved Branding Controls
&lt;/h3&gt;

&lt;p&gt;Brand Title, Brand Subtitle, and Logo Source have been enhanced with new typography, spacing, alignment, and shadow options. Logo rendering now supports object-fit, position, margin, and custom sizing, giving you complete control over brand presentation.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Enhanced Account Management Customization
&lt;/h3&gt;

&lt;p&gt;Account pages now support deeper customization through dedicated sections for Page, Card, Card Header, Card Body, Nav Menu, and Nav Button. Backgrounds, spacing, typography, and hover/selected states can be configured independently for a polished and consistent user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Upgrading from 2.x
&lt;/h2&gt;

&lt;p&gt;Upgrading to 3.0 is straightforward: update your NuGet packages (&lt;code&gt;IdentitySuite&lt;/code&gt; and &lt;code&gt;IdentitySuite.EntityFrameworkCore&lt;/code&gt;) to version 3.0.0, enable &lt;strong&gt;Apply migrations&lt;/strong&gt; in your Database settings, and start your application — the required migrations are applied automatically on startup, no manual database work needed.&lt;/p&gt;

&lt;p&gt;Existing client themes remain fully compatible with the new theming system, so no action is required after upgrading. If you'd like to adopt the new Theme Builder defaults on an existing client, you can reset the theme at any time from Configuration → Theme Editor.&lt;/p&gt;

&lt;p&gt;If your project overrides IdentitySuite's controller endpoint delegates, note that their signatures have changed in 3.0 — see the &lt;a href="https://identitysuite.net/documentation/migrations" rel="noopener noreferrer"&gt;migration guide&lt;/a&gt; for details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ready to Explore IdentitySuite 3.0?
&lt;/h2&gt;

&lt;p&gt;The fastest way to get started is through our example projects repository — ready-to-run sample applications and pre-built client configurations for several common scenarios, so you can have a working setup without writing configuration from scratch:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/spin973/IdentitySuite" rel="noopener noreferrer"&gt;https://github.com/spin973/IdentitySuite&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;IdentitySuite's core identity server — OIDC/OAuth 2.0 flows, user and client management, full configuration — is free with no time limit for deployments up to 1 client and 100 users. Premium features like the Theme Builder shown in this article, along with the Dashboard and Email Template Builder, are available as a full 30-day preview on the Free plan, so you can try them before deciding whether to upgrade. Paid plans start at €349/year, with a 14-day no-questions-asked refund.&lt;/p&gt;

&lt;p&gt;Full documentation: &lt;a href="https://identitysuite.net/documentation" rel="noopener noreferrer"&gt;identitysuite.net/documentation&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>aspnetcore</category>
      <category>release</category>
    </item>
    <item>
      <title>What is OpenIddict: the .NET framework developers choose for OAuth 2.0 and OpenID Connect</title>
      <dc:creator>Stefano Pinato</dc:creator>
      <pubDate>Fri, 10 Jul 2026 06:35:09 +0000</pubDate>
      <link>https://dev.to/_stefano_pinato/what-is-openiddict-the-net-framework-developers-choose-for-oauth-20-and-openid-connect-47io</link>
      <guid>https://dev.to/_stefano_pinato/what-is-openiddict-the-net-framework-developers-choose-for-oauth-20-and-openid-connect-47io</guid>
      <description>&lt;p&gt;I've been writing a short series on OpenIddict basics while preparing IdentitySuite's v3.0 release — here's part 1.&lt;/p&gt;

&lt;h2&gt;
  
  
  The .NET framework developers choose for OAuth 2.0 and OpenID Connect
&lt;/h2&gt;

&lt;p&gt;At some point in every .NET developer's journey, the same question comes up: &lt;strong&gt;how do I handle authentication properly?&lt;/strong&gt; Not just a login form — but token issuance, authorization flows, secure API access, and all the moving parts that modern applications require.&lt;/p&gt;

&lt;p&gt;If you have been researching this topic, you have probably come across &lt;strong&gt;OpenIddict&lt;/strong&gt;. This article explains what it is, what it actually does, and why so many developers in the .NET ecosystem rely on it.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is OpenIddict?
&lt;/h3&gt;

&lt;p&gt;OpenIddict is an &lt;strong&gt;open-source framework for ASP.NET Core&lt;/strong&gt; that allows you to add a fully compliant OAuth 2.0 and OpenID Connect authorization server to your application. In plain terms: it is the component responsible for issuing and validating the tokens that your applications and APIs use to authenticate users and authorize requests.&lt;/p&gt;

&lt;p&gt;It is not a hosted service, a SaaS product, or a cloud platform. It is a library you add to your .NET project, giving you complete control over where it runs and how it is configured.&lt;/p&gt;

&lt;p&gt;OpenIddict is maintained by &lt;a href="https://documentation.openiddict.com/" rel="noopener noreferrer"&gt;Kévin Chalet&lt;/a&gt; and has been actively developed for years. It is &lt;strong&gt;certified by the OpenID Foundation&lt;/strong&gt;, which means it has passed formal conformance tests against the OpenID Connect specification — not a minor detail when security is involved.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;OpenID Foundation Certification&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Certification means that OpenIddict's implementation has been independently verified to comply with the OpenID Connect specification. For developers, this translates to one less thing to worry about: the protocol behavior is correct by design.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  How it fits into the .NET ecosystem
&lt;/h3&gt;

&lt;p&gt;One of the reasons OpenIddict is popular in the .NET world is that it does not try to replace what already exists — it complements it.&lt;/p&gt;

&lt;p&gt;OpenIddict integrates naturally with &lt;strong&gt;ASP.NET Core Identity&lt;/strong&gt;, Microsoft's user management system. Identity handles the user store: creating accounts, hashing passwords, managing roles and claims. OpenIddict sits on top of it and handles the protocol layer: deciding when to issue a token, what claims to include, and how to respond to authorization requests.&lt;/p&gt;

&lt;p&gt;For persistence, OpenIddict uses &lt;strong&gt;Entity Framework Core&lt;/strong&gt;, which means it works with the same database you are probably already using — SQL Server, PostgreSQL, or MySQL. Applications, tokens, and authorizations are stored as regular EF Core entities, queryable and manageable like any other data in your system.&lt;/p&gt;

&lt;p&gt;This tight integration with the existing .NET stack is intentional. Rather than introducing new abstractions and paradigms, OpenIddict speaks the same language as the rest of your application.&lt;/p&gt;

&lt;h3&gt;
  
  
  What OpenIddict actually handles
&lt;/h3&gt;

&lt;p&gt;To understand what OpenIddict does, it helps to look at what an authorization server is responsible for. When a user logs into your application, or when one service needs to call another securely, a series of standardized exchanges takes place. OpenIddict implements all of them.&lt;/p&gt;

&lt;p&gt;Concretely, it exposes and manages the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Authorization endpoint&lt;/strong&gt; — where users are redirected to authenticate and consent&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token endpoint&lt;/strong&gt; — where authorization codes or credentials are exchanged for tokens&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UserInfo endpoint&lt;/strong&gt; — where applications retrieve profile information about the authenticated user&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Introspection endpoint&lt;/strong&gt; — where resource servers validate tokens without parsing them directly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Revocation endpoint&lt;/strong&gt; — where tokens can be explicitly invalidated&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Discovery endpoint&lt;/strong&gt; — the &lt;code&gt;/.well-known/openid-configuration&lt;/code&gt; document that client applications use to configure themselves automatically&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It also supports all the major OAuth 2.0 grant types: Authorization Code (with and without PKCE), Client Credentials, Refresh Token, and Device Authorization.&lt;/p&gt;

&lt;p&gt;To give you a concrete sense of what this looks like in code, here is a minimal example of how OpenIddict is registered in an ASP.NET Core application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddOpenIddict&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddCore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseEntityFrameworkCore&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
               &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UseDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ApplicationDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;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;AddServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetAuthorizationEndpointUris&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/connect/authorize"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
               &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetTokenEndpointUris&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/connect/token"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
               &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetUserinfoEndpointUris&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/connect/userinfo"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AllowAuthorizationCodeFlow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
               &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AllowRefreshTokenFlow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
               &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RequireProofKeyForCodeExchange&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddDevelopmentEncryptionCertificate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
               &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddDevelopmentSigningCertificate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseAspNetCore&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
               &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnableAuthorizationEndpointPassthrough&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
               &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnableTokenEndpointPassthrough&lt;/span&gt;&lt;span class="p"&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;AddValidation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseLocalServer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseAspNetCore&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;This is a working starting point — but it is also just the beginning. A production-ready configuration requires handling certificates properly, configuring token lifetimes, securing endpoints, registering client applications, and more. The flexibility of OpenIddict means all of this is possible, but it also means the responsibility falls on the developer to get it right.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Flexibility comes with responsibility&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;OpenIddict gives you all the building blocks. How you assemble them — and whether the result is secure and standards-compliant — depends on the decisions you make during configuration. This is not a criticism of the library; it is simply the nature of a general-purpose framework.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Why developers choose it
&lt;/h3&gt;

&lt;p&gt;Several factors explain why OpenIddict has established itself as a reference choice in the .NET space:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open source with a permissive license.&lt;/strong&gt; OpenIddict is released under the Apache 2.0 license, which means you can use it freely in commercial projects without licensing fees or usage restrictions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Active and transparent development.&lt;/strong&gt; The project is actively maintained, with a public roadmap, regular releases, and a responsive issue tracker. When a security vulnerability is discovered or a new specification is published, updates follow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Standards compliance, verified.&lt;/strong&gt; As mentioned, OpenIddict holds official OpenID Connect certification. This is not self-declared — it is the result of passing a formal test suite administered by the OpenID Foundation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No external dependencies beyond the .NET stack.&lt;/strong&gt; Unlike some alternatives that require specific infrastructure or cloud services, OpenIddict runs wherever .NET runs. On-premises, in Docker, on Azure, on a Raspberry Pi — the deployment model is entirely yours to decide.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A strong and growing community.&lt;/strong&gt; Stack Overflow, GitHub Discussions, and various .NET communities have built up a solid body of knowledge around OpenIddict. Finding answers to common configuration questions is increasingly straightforward.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrapping up
&lt;/h3&gt;

&lt;p&gt;OpenIddict is a mature, certified, and well-maintained framework that brings OAuth 2.0 and OpenID Connect to the .NET ecosystem without forcing you outside the tools you already know. It handles the protocol complexity so you can focus on your application — provided you configure it correctly.&lt;/p&gt;

&lt;p&gt;And that last part — configuring it correctly — is where things get interesting. In the &lt;a href="https://identitysuite.net/blog/identitysuite/openiddict-configuration-pitfalls" rel="noopener noreferrer"&gt;next article in this series&lt;/a&gt;, we will look at the most common mistakes developers make when setting up OpenIddict from scratch, and why getting those details wrong can have real security consequences.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>aspnetcore</category>
      <category>oauth</category>
    </item>
  </channel>
</rss>
