<?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: FusionAuth</title>
    <description>The latest articles on DEV Community by FusionAuth (@fusionauth).</description>
    <link>https://dev.to/fusionauth</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%2F139081%2Fb4ef859c-da27-4126-934a-fda3a64f70e9.png</url>
      <title>DEV Community: FusionAuth</title>
      <link>https://dev.to/fusionauth</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fusionauth"/>
    <language>en</language>
    <item>
      <title>AI didn’t create the identity problem. It removed the speed limit.</title>
      <dc:creator>FusionAuth</dc:creator>
      <pubDate>Mon, 31 Aug 2026 18:40:03 +0000</pubDate>
      <link>https://dev.to/fusionauth/ai-didnt-create-the-identity-problem-it-removed-the-speed-limit-pbl</link>
      <guid>https://dev.to/fusionauth/ai-didnt-create-the-identity-problem-it-removed-the-speed-limit-pbl</guid>
      <description>&lt;p&gt;After 30 years working in tech across infrastructure, security, dev teams, and product development, one thing has always remained true.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Never believe a new technology means you can throw out the old rules.&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
The fundamentals remain because new technology builds on them, changes where they apply, and often raises the consequences when you get them wrong.&lt;/p&gt;

&lt;p&gt;AI is no exception.&lt;/p&gt;

&lt;p&gt;AI is probabilistic, and agents can reason, make decisions, interact with other systems, and increasingly take action without a human approving every step. But the security questions underneath all of that are familiar.&lt;/p&gt;

&lt;p&gt;Who is this?&lt;/p&gt;

&lt;p&gt;Who or what are they acting for?&lt;/p&gt;

&lt;p&gt;Who are they talking to?&lt;/p&gt;

&lt;p&gt;What are they allowed to do?&lt;/p&gt;

&lt;p&gt;What can they trust?&lt;/p&gt;

&lt;p&gt;What did they actually do?&lt;/p&gt;

&lt;p&gt;AI didn’t create most of these problems. It removed the speed limit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Humans operate at human speed. Agents don’t.
&lt;/h2&gt;

&lt;p&gt;For most of the history of identity, we designed systems around people.&lt;/p&gt;

&lt;p&gt;A person shows up, proves who they are, gets access, and does something. They click, type, stop to think, go to lunch, and eventually go to sleep.&lt;/p&gt;

&lt;p&gt;Those limitations matter because they put a natural ceiling on how quickly a person can exercise their access, while an AI agent can operate continuously, call APIs, access services, interact with other agents and authorization servers, and exercise delegated authority thousands of times faster than the person whose authority it’s using.&lt;/p&gt;

&lt;p&gt;A permission that’s slightly too broad might be exercised a handful of times during someone’s working day, but an autonomous system can hit that same weakness again and again at machine speed.&lt;/p&gt;

&lt;p&gt;In our 2026 State of AI &amp;amp; Identity Report, 88% of technology leaders told us AI deployment is outpacing their identity and security infrastructure.&lt;/p&gt;

&lt;p&gt;There is always a competitor moving faster, a customer asking when something will ship, or an executive asking why you’re not doing what everyone else seems to be doing, so companies are going to keep shipping AI.&lt;/p&gt;

&lt;p&gt;Policy alone won’t protect the systems those agents can reach. The controls have to exist in the architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Probabilistic intelligence needs deterministic boundaries
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;AI is probabilistic. Authorization can’t be.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A model can be 87% confident about what you meant, but your identity infrastructure can’t be 87% confident that an agent is allowed to access your customer database.&lt;/p&gt;

&lt;p&gt;The agent can decide the next action it wants to take, while identity determines whether it has the authority to take it.&lt;/p&gt;

&lt;p&gt;That authority originates with a person or organization, so if I give an agent permission to act on my behalf, its autonomy shouldn’t expand the authority I’ve delegated to it.&lt;/p&gt;

&lt;p&gt;As agents become more capable, identity needs to provide certainty.&lt;/p&gt;

&lt;p&gt;Who or what is requesting access?&lt;/p&gt;

&lt;p&gt;Whose authority are they exercising?&lt;/p&gt;

&lt;p&gt;What are they allowed to access?&lt;/p&gt;

&lt;p&gt;Under which conditions?&lt;/p&gt;

&lt;p&gt;Where did the authorization come from?&lt;/p&gt;

&lt;p&gt;Can I see when any of this changes?&lt;/p&gt;

&lt;p&gt;FusionAuth 1.69 strengthens several of the controls behind those questions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Strengthening the identity control plane in FusionAuth 1.69
&lt;/h2&gt;

&lt;p&gt;FusionAuth 1.69 adds issuer identification, tighter control over trusted cryptographic keys, better visibility into non-human identities, and easier use of sender-constrained access tokens in browser applications.&lt;/p&gt;

&lt;p&gt;These controls already protect applications and APIs, but AI increases how often they’re exercised and how quickly a weak assumption can turn into a security problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do I know who I’m talking to?
&lt;/h2&gt;

&lt;p&gt;Modern identity architectures can involve multiple authorization servers, while agentic architectures will add more connections between applications, APIs, agents, and the systems authorizing them.&lt;/p&gt;

&lt;p&gt;When a client receives an authorization response, it needs to confirm that the response came from the authorization server it intended to use because otherwise it can begin an authorization flow with one server and accept a response originating from another. This is an authorization server mix-up attack.&lt;/p&gt;

&lt;p&gt;FusionAuth 1.69 adds support for RFC 9207, OAuth 2.0 Authorization Server Issuer Identification. We enabled it by default, making us the only commercially supported CIAM provider to do so.&lt;/p&gt;

&lt;p&gt;With RFC 9207, the authorization response includes the identity of the server that issued it. While FusionAuth includes issuer identification in authorization responses by default, the client still needs to validate that identifier against the authorization server it intended to use.&lt;/p&gt;

&lt;p&gt;The client can then verify where the authorization response came from instead of assuming.&lt;/p&gt;

&lt;p&gt;Am I trusting more than I need to?&lt;br&gt;
JWT verification confirms that a token was signed by a trusted key, which makes the size of that trusted key pool important.&lt;/p&gt;

&lt;p&gt;If an application only needs to trust two verification keys but will accept any of twenty, you’ve created eighteen trust relationships you don’t need.&lt;/p&gt;

&lt;p&gt;FusionAuth 1.69 adds Signature Verification Key Selection, so an application can explicitly control which keys it accepts when verifying JWT signatures.&lt;/p&gt;

&lt;p&gt;Verify which authorization server you’re dealing with, then limit the signing keys the application will accept from it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Because verification is now strictly scoped to configured keys, deployments using external JWT or SAML identity providers or active key rotations should review the &lt;a href="https://fusionauth.io/docs/operate/troubleshooting/1-69-0-migration-guide" rel="noopener noreferrer"&gt;1.69 Migration Guide&lt;/a&gt; before upgrading.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Can I see my non-human identities changing?
&lt;/h2&gt;

&lt;p&gt;FusionAuth 1.69 adds an &lt;code&gt;AI Agent&lt;/code&gt; Entity Type, so you can explicitly distinguish AI agents from other non-human entities, and it adds Entity lifecycle webhooks for create, update, and delete events.&lt;/p&gt;

&lt;p&gt;Your security and audit systems can now track when an AI agent appears, when its configuration changes, and when it’s removed, while those events can flow from FusionAuth into the systems responsible for monitoring, auditing, and automation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happens if someone steals the token?
&lt;/h2&gt;

&lt;p&gt;Standard bearer access tokens work like cash: whoever holds the token can use it. If a bearer token is stolen out of a browser, any attacker can replay it.&lt;/p&gt;

&lt;p&gt;DPoP, or Demonstrating Proof of Possession, turns bearer tokens into sender-constrained tokens. Access tokens are cryptographically bound to the client that requested them, and the client proves possession of its private key on every request. Therefore, stealing the access token alone isn’t enough to replay it from another client.&lt;/p&gt;

&lt;p&gt;FusionAuth has supported DPoP server-side since version 1.63, while React, Angular, and Vue SDK support shipped on August 5, 2026, making DPoP native and easy to use from browser applications without writing custom JOSE cryptography.&lt;/p&gt;

&lt;p&gt;Your API still needs to validate the DPoP proof when the protected resource is accessed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some security work is boring. It still matters.
&lt;/h2&gt;

&lt;p&gt;There’s more in 1.69.&lt;/p&gt;

&lt;p&gt;We’ve added SAML configuration flexibility, updated password hashing import support, improved group auditing, updated runtime support and dependencies, and fixed security issues across the platform.&lt;/p&gt;

&lt;p&gt;Security products need this work because dependencies need patching, runtime support needs updating, cryptographic practices change, and audit requirements grow.&lt;/p&gt;

&lt;p&gt;When identity controls access to your users, applications, APIs, machines, services, data, and AI agents, keeping dependencies and runtimes current is part of the job.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI raises the stakes on the fundamentals
&lt;/h2&gt;

&lt;p&gt;AI agents will get more capable and more autonomous, and the amount of authority we delegate to them will grow with that capability.&lt;/p&gt;

&lt;p&gt;That puts a lot of pressure on identity infrastructure designed when access happened at human speed, so FusionAuth 1.69 strengthens that infrastructure today while we continue building for the agent authorization problems coming next.&lt;/p&gt;

&lt;p&gt;AI is probabilistic. The identity controlling what it can do can’t be.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>authentication</category>
      <category>fusionauth</category>
    </item>
    <item>
      <title>Why Risk-Based MFA is a Game Changer for User Experience</title>
      <dc:creator>FusionAuth</dc:creator>
      <pubDate>Wed, 12 Aug 2026 17:55:01 +0000</pubDate>
      <link>https://dev.to/fusionauth/why-risk-based-mfa-is-a-game-changer-for-user-experience-3ged</link>
      <guid>https://dev.to/fusionauth/why-risk-based-mfa-is-a-game-changer-for-user-experience-3ged</guid>
      <description>&lt;p&gt;Security measures often feel like they're just making life harder for customers. The problem is that too much friction can work against security. Frustrated users are more likely to reuse passwords, choose weaker credentials, or fall for phishing attempts, creating exactly the kinds of openings attackers look for.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://fusionauth.io/articles/authentication/multi-factor-authentication" rel="noopener noreferrer"&gt;Multi-factor authentication (MFA)&lt;/a&gt; adds another layer of protection when passwords are stolen or compromised. But for customer-facing applications, that protection comes with a tradeoff: every additional authentication step creates friction. If MFA challenges appear too often or at the wrong moments, customers may abandon the login, the transaction, or even the service altogether.&lt;/p&gt;

&lt;p&gt;That's where risk-based MFA (sometimes known as adaptive MFA) comes in.&lt;/p&gt;

&lt;p&gt;Rather than challenging every login every time, it adjusts authentication requirements based on the actual risk of each attempt. The idea is simple: users who log in from a two year-old laptop at the same time every day don't need to be challenged like someone logging in from a new device at 3am from a country they've never visited. Risk-based MFA can tell the difference. Standard MFA cannot.&lt;/p&gt;

&lt;p&gt;While early versions of risk-based MFA required significant configuration work, the category has matured considerably. Modern implementations, like &lt;a href="https://fusionauth.io/blog/intelligent-mfa" rel="noopener noreferrer"&gt;Intelligent MFA in FusionAuth 1.68&lt;/a&gt;, handle the risk-scoring engine automatically, without custom code or manual triggers.&lt;/p&gt;

&lt;p&gt;Risk-based MFA remains a critical component of any modern authentication strategy. This article walks through what risk-based MFA solves, how it works, and what to look for in a risk-based MFA implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations of Traditional MFA
&lt;/h2&gt;

&lt;p&gt;A traditional approach to MFA is usually a huge step up in security, adding an additional layer of authentication that makes &lt;a href="https://cdn-dynmedia-1.microsoft.com/is/content/microsoftcorp/microsoft/final/en-us/microsoft-brand/documents/MFA-Microsoft-Research-Paper-update.pdf" rel="noopener noreferrer"&gt;unauthorized access&lt;/a&gt; hard for most attackers.&lt;/p&gt;

&lt;p&gt;But like most things in life, MFA comes with certain drawbacks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Users Find MFA Inconvenient
&lt;/h3&gt;

&lt;p&gt;MFA may stop attackers, but customers are less interested in the security architecture behind a login than in getting where they need to go quickly.&lt;/p&gt;

&lt;p&gt;Every additional authentication step creates friction. Customers may need to switch between apps or devices, retrieve a code, approve a push notification, or wait for an SMS message that never arrives. Even a small interruption can feel disproportionately frustrating when someone is simply trying to access an account, complete a purchase, or use a service.&lt;/p&gt;

&lt;p&gt;That frustration matters. Customers have little patience for authentication that feels unnecessarily difficult, especially when competing services are only a click away. Too many MFA challenges can lead to abandoned logins, increased support requests, and lower conversion or engagement.&lt;/p&gt;

&lt;p&gt;Strong authentication has to protect the account without turning every login into an obstacle course.&lt;/p&gt;

&lt;h3&gt;
  
  
  Not All MFA Is More Secure
&lt;/h3&gt;

&lt;p&gt;Another important thing to keep in mind is that some methods of MFA can actually create even greater vulnerabilities.&lt;/p&gt;

&lt;p&gt;For example, SMS and email authentication are the least secure MFA authentication methodologies. Getting a six-digit code in an email account that's not secured by MFA and might have much less robust password protection can leave you exposed.&lt;/p&gt;

&lt;p&gt;Likewise, SMS MFA is vulnerable to hackers that perform &lt;a href="https://en.wikipedia.org/wiki/SIM_swap_scam" rel="noopener noreferrer"&gt;SIM swap&lt;/a&gt; attacks. They can clone SIM cards to have messages and calls redirected to the attacker's phone.&lt;/p&gt;

&lt;p&gt;MFA for the sake of MFA is not the same as using MFA to strengthen security.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Risk-Based MFA?
&lt;/h2&gt;

&lt;p&gt;Traditional MFA applies the same authentication requirements to every login. Risk-based MFA adjusts those requirements based on the level of risk associated with each authentication attempt.&lt;/p&gt;

&lt;p&gt;That means a routine login can pass with minimal friction, while a suspicious attempt triggers additional verification. Instead of forcing every customer through the same MFA flow, organizations can apply stronger authentication only when the situation warrants it.&lt;/p&gt;

&lt;p&gt;For customer-facing applications, that balance matters. Risk-based MFA helps protect accounts without adding unnecessary friction to every login.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Risk-Based MFA Detects Risk
&lt;/h2&gt;

&lt;p&gt;Risk-based MFA evaluates each login against defined signals and rules to determine whether additional authentication is required. Those signals can include device, location, IP address, network, recent authentication activity, and conditions such as impossible travel.&lt;/p&gt;

&lt;p&gt;An organization might configure a policy that requires MFA when a customer signs in from a new device, connects from a malicious IP address, or attempts to authenticate from an unexpected location. When those conditions are met, the corresponding MFA challenge is triggered.&lt;/p&gt;

&lt;p&gt;Because the decision is based on explicit signals and configured rules, security teams can understand why a login was challenged and adjust their policies as risk requirements change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of Risk-Based MFA
&lt;/h2&gt;

&lt;p&gt;The biggest advantage of risk-based MFA is that it makes stronger authentication more selective. Legitimate customers encounter fewer unnecessary challenges, while higher-risk login attempts receive additional scrutiny.&lt;/p&gt;

&lt;p&gt;That improves more than security. Fewer interruptions can create a smoother customer experience, reduce abandoned logins and support requests, and help protect conversion and retention. At the same time, security teams gain more control over when stronger authentication is required and why.&lt;/p&gt;

&lt;h3&gt;
  
  
  Built-In Risk Scoring Simplifies Authentication Management
&lt;/h3&gt;

&lt;p&gt;Risk-based MFA is easier to manage when the risk engine is built into the identity platform rather than added as a separate service. The platform already has access to the user database, device history, and login events needed to evaluate risk, so those signals do not have to be stitched together across multiple systems.&lt;/p&gt;

&lt;p&gt;That also makes it easier to apply the same risk policy across every application the identity platform protects. A customer can receive consistent risk treatment whether they are signing in through a web app, mobile app, or API.&lt;/p&gt;

&lt;p&gt;Because the risk decision happens inside the identity platform, those events can also flow into the rest of the security stack through webhooks and integrations. Security teams can see MFA challenges alongside other threat signals and automate responses without having to operate a separate risk service.&lt;/p&gt;

&lt;h3&gt;
  
  
  Risk-Based MFA Strikes a Better Balance between Simplicity and Security
&lt;/h3&gt;

&lt;p&gt;Risk-based MFA strikes a more acceptable balance between security and simplicity.&lt;/p&gt;

&lt;p&gt;Since risk-based MFA works with behavioral signals, geolocation, and trusted IPs, users who regularly work within the same "safe" conditions are not prompted for MFA authentication. In internal networks, risk-based MFA can even be integrated with single sign-on (SSO). That means those who work on an SSO-enabled device will not even need a password to log in as long as they work from their safe device and within trusted boundaries (IPs, geolocation, etc.).&lt;/p&gt;

&lt;p&gt;Adding simplicity to security is particularly useful in certain situations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Where the user is your customer.&lt;/strong&gt; You'll notice that e-commerce services such as eBay or Amazon ask for little to no authentication when you log in from the same network and device as usual. But they will prompt you for MFA for more sensitive tasks such as adding or removing a credit card.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In the healthcare industry.&lt;/strong&gt; Healthcare workers are governed by strict legislation such as &lt;a href="https://www.cdc.gov/phlp/publications/topic/hipaa.html" rel="noopener noreferrer"&gt;HIPAA&lt;/a&gt; to protect patients' &lt;a href="https://www.investopedia.com/terms/p/personally-identifiable-information-pii.asp" rel="noopener noreferrer"&gt;personally identifiable information (PII)&lt;/a&gt;. Risk-based MFA allows them to work more seamlessly while complying with security regulations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On mobile devices.&lt;/strong&gt; Prompting users for excessive written credentials and asking them to swap between apps for authentication is especially grating on mobile devices. Risk-based MFA makes simplicity and fluency a reality with smartphones.
### Risk-Based MFA Can Be Easier to Implement and Manage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Like many security initiatives, risk-based MFA can require an investment in technology, implementation, and ongoing management. The size of that investment depends heavily on the identity platform.&lt;/p&gt;

&lt;p&gt;Amazon Cognito, for example, places risk-based adaptive authentication in its Plus tier. Enabling it requires configuring threat protection, setting MFA appropriately, choosing enforcement modes and risk responses, and, for some application flows, passing additional context data such as IP address, device information, and request headers so Cognito can evaluate risk accurately. The Plus tier is also priced per monthly active user, with no general free tier for those users.&lt;/p&gt;

&lt;p&gt;FusionAuth takes a simpler approach to both implementation and pricing. Intelligent MFA evaluates logins against ten configurable risk signals and is included in every paid FusionAuth plan without a separate add-on or additional per-user charge for the feature itself.&lt;/p&gt;

&lt;p&gt;That difference matters because the value of risk-based MFA depends on how practical it is to deploy and maintain. Lower implementation complexity, fewer moving parts, and more predictable costs make it easier to adopt the capability broadly and keep it working as authentication requirements evolve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Intelligent MFA Takes It Further
&lt;/h2&gt;

&lt;p&gt;The principles above describe what risk-based MFA is supposed to do. But in practice, risk-based MFA platforms differ significantly in how much context they evaluate and where that risk evaluation happens.&lt;/p&gt;

&lt;p&gt;First, the number and variety of risk signals matter. A system that looks at only a few conditions has less context to work with than one that evaluates device trust, IP reputation, impossible travel, suspicious browsers, bot activity, dormant accounts, stale credentials, and recent account changes. The more relevant signals available to the decision, the better equipped the system is to distinguish a routine login from one that deserves additional verification.&lt;/p&gt;

&lt;p&gt;Where that risk evaluation happens matters too. Some platforms send authentication data to a vendor-hosted service for scoring. For organizations with strict data residency requirements, regulated environments, or security policies that limit where identity data can travel, keeping risk evaluation inside their own infrastructure can be an important requirement.&lt;/p&gt;

&lt;p&gt;That becomes even more critical in air-gapped environments, where authentication systems may have no connection to the public internet at all. Risk-based MFA that depends on an external scoring service simply won't work there, so deployment architecture becomes part of the security decision.&lt;/p&gt;

&lt;p&gt;FusionAuth 1.68 introduces &lt;a href="https://fusionauth.io/feature/multifactor-authentication" rel="noopener noreferrer"&gt;Intelligent MFA&lt;/a&gt;, a built-in risk-scoring engine that addresses both of these gaps. Here's how it works.&lt;/p&gt;

&lt;h3&gt;
  
  
  The 10-Signal Risk Engine
&lt;/h3&gt;

&lt;p&gt;Every login is evaluated against up to ten independent signals before a challenge decision is made. Each signal is scored HIGH, MEDIUM, or LOW:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Risk Signal&lt;/th&gt;
&lt;th&gt;Behavior Identifier&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Impossible Travel&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;The account just logged in from a location physically impossible to reach since the last login, which strongly suggests credentials are being used by two different parties. One of them could be an attacker.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Untrusted Device&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;The user never marked this device as "remembered" during a prior MFA prompt, so we have no standing signal that they personally vouch for it. Absence of that trust marker warrants re-verifying identity.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Unrecognized Device&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;This device has never been seen on the account before. New hardware is a classic indicator of credential theft or session hijacking, so confirm the person is really them.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Blocklisted IP&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;The login originates from an IP on a known-malicious set tied to attacks, botnets, or abuse. Traffic from these sources is far more likely to be hostile.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Stale Credentials&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;The password is many months or even years old, giving it a long window to have leaked in a breach or been guessed. Stale credentials are more likely already compromised.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Suspicious Password Reset&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;The password was changed recently, which is exactly what an attacker does right after taking over an account to lock out the real owner. A fresh change so recently is suspicious until proven legitimate.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Account Owner Change&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;A login identifier was added or changed recently, a common takeover move to hijack recovery and notifications. The recency of the change is the red flag, and risk drops the longer ago it happened.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Dormant Account Reactivation&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;The account has been dormant for a long time, a prime target since the real owner isn't watching for unauthorized access. Reactivation after long silence often signals takeover.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Suspicious Browser&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;The browser/client string matches a list of known-bad user agents associated with attack tooling. Such fingerprints rarely belong to genuine human sessions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Bot Detected&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Input timing indicates a bot or automated system rather than a human. Automation at the login screen points to credential stuffing or scripted abuse.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The individual signal scores combine into a single composite. More HIGH signals raise that average, but the result is still bucketed as LOW, MEDIUM, or HIGH. You configure the policy: challenge only on HIGH, or challenge on MEDIUM and above.&lt;/p&gt;

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

&lt;p&gt;A returning user on a known device with a recent login and a clean IP scores LOW and passes through with no friction. A login from an unrecognized device on a flagged IP, with a password unchanged for months, stacks HIGH across multiple signals, triggering the policy automatically. No custom code required.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deterministic Scoring: Why It Matters for Compliance
&lt;/h3&gt;

&lt;p&gt;Most vendor risk engines use machine learning (ML). ML-based scoring can catch patterns a rules-based system might miss, but it has a real cost for compliance teams: it can't explain itself at the signal level. When an auditor asks why a specific user was challenged on a specific date, you can't get a documented and reproducible answer.&lt;/p&gt;

&lt;p&gt;Intelligent MFA uses deterministic scoring. Every challenge decision is driven by named signals, each mapped to a risk level, combined into a composite score. The composite score is logged in your event log. With Enterprise, the triggered threat signals are available to your SIEM via webhooks, with the full per-signal scores recorded in your event log. So when the question comes up (and in SOC 2, ISO 27001, and NIST 800-63B reviews, it will), you have a documented, auditable answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Risk-based MFA represents an important shift in how organizations approach authentication. Instead of treating every login as equally trustworthy or suspicious, it evaluates the context of each attempt and responds accordingly.&lt;/p&gt;

&lt;p&gt;Legitimate customers face fewer unnecessary challenges, while suspicious logins receive stronger verification. That means a better customer experience, fewer abandoned logins, and fewer authentication-related support issues.&lt;/p&gt;

&lt;p&gt;The business impact is just as important. Less login friction can improve conversion, reduce churn, and support stronger gross revenue retention. Fewer support requests can lower service costs, while stronger protection against account takeover helps reduce fraud losses, remediation costs, and damage to customer trust.&lt;/p&gt;

&lt;p&gt;As risk-based MFA continues to evolve, organizations have access to richer risk signals, more transparent decision-making, and greater flexibility in how authentication policies are applied. The question is no longer whether risk-based MFA improves on traditional MFA. It's how effectively your implementation can distinguish between trusted users and genuine threats.&lt;/p&gt;

&lt;p&gt;To see how Intelligent MFA handles a real login flow, &lt;a href="https://fusionauth.io/contact" rel="noopener noreferrer"&gt;request a demo&lt;/a&gt;. You'll walk through a scored session (one clean, one suspicious) and see exactly where the policy challenges and where it doesn't.&lt;/p&gt;

</description>
      <category>mfa</category>
      <category>authentication</category>
      <category>ux</category>
    </item>
    <item>
      <title>I Just Want Authentication To Work</title>
      <dc:creator>FusionAuth</dc:creator>
      <pubDate>Wed, 22 Nov 2023 23:32:35 +0000</pubDate>
      <link>https://dev.to/fusionauthio/i-just-want-authentication-to-work-1idb</link>
      <guid>https://dev.to/fusionauthio/i-just-want-authentication-to-work-1idb</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally posted by Alex Patterson @ FusionAuth.io&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Authentication is the process of verifying the identity of a user or entity. It is a fundamental security measure that is used in a wide variety of applications, including web applications, mobile apps, and APIs. The thing is, as a developer with over 20 years of experience, I just don't care about figuring it out! I just want it to work!!&lt;/p&gt;

&lt;p&gt;There are many different ways to implement authentication, but the most common approach is to use a username and password. Yep, just like back in 1960 when &lt;a href="https://youtu.be/KtY3L5tDN_E?si=BATB3BzJJFpWsHmB" rel="noopener noreferrer"&gt;The Everly Brothers&lt;/a&gt; had one of the top songs out there, this method is still most popular today. Just as the Everly Brothers' time at the top of the charts has passed, so has the time for passwords. I don't want to hear about them anymore!&lt;/p&gt;

&lt;p&gt;A more modern approach is to use a single sign-on (SSO) solution. SSO solutions allow users to log in to multiple applications using a single set of credentials. This can be convenient for users, as they do not have to remember multiple usernames and passwords. This method came about around the same time Eminem hit the &lt;a href="https://youtu.be/6mPCy9LMxTI?si=5A2I-N1neb_8rGOl" rel="noopener noreferrer"&gt;billboard top 100&lt;/a&gt; for the first time. SSO often has the problem of including the first login requirement of using a username and password to this day. Even Eminem made some changes and remains relevant!&lt;/p&gt;

&lt;p&gt;My point is that authentication is an important security measure, but it can also be complex to implement. This is why we have been hanging on to these old methods for so long! When you are creating a new application (unless it is an &lt;em&gt;authentication&lt;/em&gt; application), the last thing you care about is user login. There are many different authentication methods to choose from, and each method has its own advantages and disadvantages. Additionally, authentication needs to be implemented in a secure way to prevent attackers from gaining unauthorized access to applications. &lt;br&gt;
But, again, all I care about is that my data is secure when creating the next &lt;a href="https://youtu.be/CKrdsGdLVQ8?si=bTp4DHKS4tlpQzfW" rel="noopener noreferrer"&gt;Napster&lt;/a&gt; so everyone can share their 1990s music with me again!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffusionauth.io%2Fimg%2Fblogs%2Fi-just-want-authentication-to-work%2Fnapster.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffusionauth.io%2Fimg%2Fblogs%2Fi-just-want-authentication-to-work%2Fnapster.png" alt="Napster app from Wikipedia"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The benefits of using an authentication service
&lt;/h2&gt;

&lt;p&gt;There are many benefits to using an authentication service. Authentication services can help you:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Save time and money: Implementing and maintaining authentication can be time-consuming and expensive. authentication services can save you the hassle of having to implement and maintain your authentication system. s&lt;/li&gt;
&lt;li&gt;Improve security: authentication services can help you to improve the security of your applications by using best practices and the latest security technologies keeping up to date with the latest security patches.&lt;/li&gt;
&lt;li&gt;Reduce the risk of compliance violations: authentication services can help you meet compliance requirements by providing features such as two-factor authentication and user provisioning.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last thing that I want is a call on Saturday night that someone hacked the password database that we built in-house two years ago and didn't maintain securely!  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffusionauth.io%2Fimg%2Fblogs%2Fi-just-want-authentication-to-work%2Fmeme-leak.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffusionauth.io%2Fimg%2Fblogs%2Fi-just-want-authentication-to-work%2Fmeme-leak.png" alt="Meme you can't leak passwords if you don't store passwords, man pointing at head"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing an authentication service
&lt;/h2&gt;

&lt;p&gt;When choosing an authentication service, there are a few factors to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Features: Consider the features that are important to you, such as two-factor authentication, user provisioning, and support for different authentication methods.&lt;/li&gt;
&lt;li&gt;Pricing: authentication services can vary in price. Compare the pricing of different services to find the best deal for your needs.&lt;/li&gt;
&lt;li&gt;Ease of use: Consider how easy the authentication service is to use. You want a service that is easy to set up and manage.&lt;/li&gt;
&lt;li&gt;Hosting: Do you need flexibility to host your instance of an authentication Provider or have them host?&lt;/li&gt;
&lt;li&gt;Integration support: Often you'll want to use an authentication service as a central user data store. You'll want to make sure you can integrate custom applications, off-the-shelf commercial software, and open-source solutions with it.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  For Developers Who Just Want It To Work
&lt;/h2&gt;

&lt;p&gt;If you are a developer who just wants authentication to work without implementing it yourself, there are a few things that you can do to make your life easier:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use an authentication service. There are many different authentication services available, both free and paid. Authentication services can save you the hassle of having to implement and maintain your authentication system.&lt;/li&gt;
&lt;li&gt;Use a framework or library that provides authentication functionality. There are many different frameworks and libraries available that provide authentication functionality. Using a framework or library can save you the time and effort of having to implement authentication yourself. If you are ready to get started check out our &lt;a href="https://dev.to/docs/quickstarts/"&gt;FusionAuth Quickstarts&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Consider that when Better Napster, wait I mean your app, starts to grow, you will want an authentication provider that can handle different devices and form factors such as mobile, desktop, and web clients.&lt;/li&gt;
&lt;li&gt;Develop a local instance or self-contained environment that you can host yourself to make development easier.
&lt;/li&gt;
&lt;li&gt;Look to your favorite framework provider and see what they are using and use an authentication framework built for that.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What You &lt;em&gt;Should&lt;/em&gt; Care About
&lt;/h2&gt;

&lt;p&gt;Now that you have authentication figured out you can start to focus on the real requirements of building an application...&lt;/p&gt;

&lt;p&gt;Picking the rest of your software components:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Framework - &lt;a href="https://remix.run/" rel="noopener noreferrer"&gt;Remix&lt;/a&gt;, &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt;, &lt;a href="https://kit.svelte.dev/" rel="noopener noreferrer"&gt;SvelteKit&lt;/a&gt;, &lt;a href="https://www.phoenixframework.org/" rel="noopener noreferrer"&gt;Pheonix Framework&lt;/a&gt;, &lt;a href="https://laravel.com/" rel="noopener noreferrer"&gt;Laravel&lt;/a&gt;, &lt;a href="https://flask.palletsprojects.com/en/3.0.x/" rel="noopener noreferrer"&gt;Flask&lt;/a&gt;, &lt;a href="https://angular.io/" rel="noopener noreferrer"&gt;Angular&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Database - &lt;a href="https://planetscale.com/" rel="noopener noreferrer"&gt;PlanetScale&lt;/a&gt;, &lt;a href="https://cloud.google.com/alloydb" rel="noopener noreferrer"&gt;AlloyDB for PostgreSQL&lt;/a&gt;, &lt;a href="https://aws.amazon.com/rds/aurora/serverless/" rel="noopener noreferrer"&gt;AWS Aurora Serverless&lt;/a&gt;, &lt;a href="https://www.cockroachlabs.com/blog/announcing-cockroachdb-serverless/" rel="noopener noreferrer"&gt;CockroachDB Serverless&lt;/a&gt;, &lt;a href="https://www.edgedb.com/" rel="noopener noreferrer"&gt;EdgeDB&lt;/a&gt;, &lt;a href="https://neon.tech/" rel="noopener noreferrer"&gt;Neon&lt;/a&gt;, &lt;a href="https://supabase.com/" rel="noopener noreferrer"&gt;Supabase&lt;/a&gt;, &lt;a href="https://www.timescale.com/" rel="noopener noreferrer"&gt;Timescale&lt;/a&gt;, &lt;a href="https://upstash.com/" rel="noopener noreferrer"&gt;Upstash&lt;/a&gt;, &lt;a href="https://grafbase.com/" rel="noopener noreferrer"&gt;Grafbase&lt;/a&gt;, &lt;a href="https://turso.tech/" rel="noopener noreferrer"&gt;Turso&lt;/a&gt;, &lt;a href="https://fauna.com/" rel="noopener noreferrer"&gt;Fauna&lt;/a&gt;, &lt;a href="https://ably.com" rel="noopener noreferrer"&gt;Ably&lt;/a&gt;, &lt;a href="https://www.convex.dev/" rel="noopener noreferrer"&gt;Convex&lt;/a&gt;, &lt;a href="https://hasura.io/" rel="noopener noreferrer"&gt;Hasura&lt;/a&gt;, &lt;a href="https://liveblocks.io/" rel="noopener noreferrer"&gt;liveblocks&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Hosting - &lt;a href="https://vercel.com/" rel="noopener noreferrer"&gt;Vercel&lt;/a&gt;, &lt;a href="https://www.netlify.com/" rel="noopener noreferrer"&gt;Netlify&lt;/a&gt;, &lt;a href="https://fly.io/" rel="noopener noreferrer"&gt;Fly.io&lt;/a&gt;, &lt;a href="https://www.cloudflare.com/" rel="noopener noreferrer"&gt;Cloudflare&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;CMS: &lt;a href="https://www.contentful.com/" rel="noopener noreferrer"&gt;Contentful&lt;/a&gt;, &lt;a href="https://www.quintype.com/" rel="noopener noreferrer"&gt;Quintype&lt;/a&gt;, &lt;a href="https://hygraph.com/" rel="noopener noreferrer"&gt;Hygraph&lt;/a&gt;, &lt;a href="https://ghost.org/publishers/" rel="noopener noreferrer"&gt;Ghost&lt;/a&gt;, &lt;a href="https://strapi.io/" rel="noopener noreferrer"&gt;Strapi&lt;/a&gt;, &lt;a href="https://www.sanity.io/" rel="noopener noreferrer"&gt;Sanity&lt;/a&gt;, &lt;a href="https://kontent.ai/" rel="noopener noreferrer"&gt;Kontent&lt;/a&gt;, &lt;a href="https://www.optimizely.com/products/orchestrate/content-management/" rel="noopener noreferrer"&gt;Optimizely&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are full backend solutions out there like &lt;a href="https://firebase.google.com/" rel="noopener noreferrer"&gt;Firebase&lt;/a&gt;, &lt;a href="https://supabase.com/" rel="noopener noreferrer"&gt;Supabase&lt;/a&gt;, and &lt;a href="https://www.appwrite.io" rel="noopener noreferrer"&gt;Appwrite&lt;/a&gt;. However, if you don't like some part of these stacks then it becomes very difficult for you to decouple your application(s). In this video our Founder and CEO talks about &lt;a href="https://youtu.be/SLc3cTlypwM?si=qFzJaeA9NTeXGSfz&amp;amp;t=834" rel="noopener noreferrer"&gt;Authentication as a Microservice&lt;/a&gt; and how to use a JWT in your APIs.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Finally
&lt;/h2&gt;

&lt;p&gt;Okay, now that I got that out of my system I am off to listen to &lt;a href="https://youtu.be/UekfKh59KOw?si=xTM0powkicUHG2Yo" rel="noopener noreferrer"&gt;Connor Price&lt;/a&gt; and log in to Amazon using my &lt;a href="https://www.aboutamazon.com/news/retail/amazon-passwordless-sign-in-passkey" rel="noopener noreferrer"&gt;face&lt;/a&gt; because it is 2023 people!&lt;/p&gt;

&lt;p&gt;Oh yeah and now the actual coding begins!!&lt;/p&gt;

&lt;p&gt;If you want authentication to just work start using &lt;a href="https://dev.to/pricing"&gt;FusionAuth today for free&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Want to get jump-started using your framework of choice? Check out our &lt;a href="https://dev.to/docs/quickstarts/"&gt;Quickstarts&lt;/a&gt;.  &lt;/p&gt;

</description>
      <category>community</category>
      <category>authentication</category>
      <category>nextjs</category>
      <category>auth</category>
    </item>
    <item>
      <title>Authentication Workflows Overview</title>
      <dc:creator>FusionAuth</dc:creator>
      <pubDate>Mon, 16 Oct 2023 15:39:32 +0000</pubDate>
      <link>https://dev.to/fusionauthio/authentication-workflows-overview-38ib</link>
      <guid>https://dev.to/fusionauthio/authentication-workflows-overview-38ib</guid>
      <description>&lt;p&gt;The landscape of applications today is broad. Similarly, the methods of authentication used is similarly varied. This section covers some of the login and authentication workflows used by applications today. These examples use FusionAuth as the IdP (identity provider), but any IdP could be used. You can use these articles to help architect and design the authentication system for your application.&lt;/p&gt;

&lt;p&gt;Keep in mind that this list is not exhaustive. Most IdPs, including FusionAuth, are capable of other forms of login. Also, there are many login workflows that we do not cover here due to security concerns with those methods.&lt;/p&gt;

&lt;p&gt;Also, these articles do not discuss the pros and cons of the different types of applications and which might be best for your needs. They focus entirely on authentication for applications. There are many articles available that cover different application types and why you should choose one over the other (such as the decision to use a native mobile application versus a responsive web application).&lt;/p&gt;

&lt;h2&gt;
  
  
  Definitions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Native login form&lt;/strong&gt; - this is a form built directly into the application rather then leveraging an external login form such as an OAuth provider&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application backend&lt;/strong&gt; - this is the backend of the application, not the IdP (i.e. not FusionAuth)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Traditional web application authentication
&lt;/h2&gt;

&lt;p&gt;Traditional web applications (webapps) use the request and response nature of the HTTP protocol along with the URL address of the browser to provide functionality to users. Many new web applications are still implemented using this method and many existing web applications use this pattern.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bGzhw4oj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/img/articles/login-authentication-workflows/login-type-get-post.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bGzhw4oj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/img/articles/login-authentication-workflows/login-type-get-post.png" alt="Login Workflows" width="530" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These applications load a web page by making a request from the browser to the server based on the URL address. The server responds to these requests with HTML, CSS &amp;amp; JavaScript. These documents are then rendered by the browser.&lt;/p&gt;

&lt;p&gt;When the user clicks a link, button or submits a form, the browser makes a new request to the server and changes the URL in the address bar. The server handles the request and returns HTML, CSS &amp;amp; JavaScript that is rendered by the browser again. The browser renders the new documents.&lt;/p&gt;

&lt;p&gt;There are only two HTTP methods supported by the browser in this style of application, &lt;code&gt;GET&lt;/code&gt; and &lt;code&gt;POST&lt;/code&gt;. The HTTP method informs the server what type of action the user took and how to handle the request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Single-page application authentication
&lt;/h2&gt;

&lt;p&gt;Single-page web applications (SPA sometimes pronounced spa or S-P-A) use a single request and response to download the application. Sometimes the entire application is retrieved on the initial request and other times only part of the application is retrieved. This initial retrieve consists of HTML, CSS and JavaScript that comprise the application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eQz8Kt3p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/img/articles/login-authentication-workflows/login-type-xmlhttprequest.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eQz8Kt3p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/img/articles/login-authentication-workflows/login-type-xmlhttprequest.png" alt="Login Workflows" width="530" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the application is retrieved, it is started by the browser, normally by invoking a JavaScript framework that bootstraps and then begins to render the application. In many cases, the HTML of the application is produced by JavaScript and the browser updates the current document dynamically.&lt;/p&gt;

&lt;p&gt;SPAs use JavaScript and call APIs to handle user interactions and input. For example, if a user clicks a link, the SPA might modify the document to render a different page or form. When a user submits a form, the SPA might call an API on the server.&lt;/p&gt;

&lt;p&gt;APIs are invoked using the &lt;code&gt;XMLHttpRequest&lt;/code&gt; functionality of browser JavaScript. This generally makes calls to REST APIs on the server. When the server responds, the JavaScript running in the browser handles the response and updates the document.&lt;/p&gt;

&lt;p&gt;Since the browser is using &lt;code&gt;XMLHttpRequest&lt;/code&gt;, it can invoke all of the standard HTTP methods including &lt;code&gt;GET&lt;/code&gt;, &lt;code&gt;POST&lt;/code&gt;, &lt;code&gt;PUT&lt;/code&gt; and &lt;code&gt;DELETE&lt;/code&gt;. The HTTP method helps inform the server what type of action the user took and how to handle the request.&lt;/p&gt;

&lt;p&gt;It is important to note that while we recommend OAuth for SPAs, it causes the browser to close the SPA and navigate to the OAuth provider. Once the OAuth workflow is complete, the browser retrieves and starts the SPA again. This process might seem somewhat heavy, but the SPA should be cached in the browser making the second startup process much faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Native mobile application authentication
&lt;/h2&gt;

&lt;p&gt;Native mobile applications are usually installed via a store and installed on the mobile device (phone, tablet, etc). These applications are started by clicking the icon on the device. The device operating system then starts the application. Once the application is started, it renders its user interface.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wUqSN2df--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/img/articles/login-authentication-workflows/login-type-native.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wUqSN2df--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/img/articles/login-authentication-workflows/login-type-native.png" alt="Login Workflows" width="476" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Native applications often call APIs to handle user interactions and input. For example, if a user clicks a button or submits a form, the application might call an API on the server. This API might be called via HTTP or some other type of protocol. Often, native applications use various libraries for making API calls simpler.&lt;/p&gt;

&lt;p&gt;Some experts recommend that native applications (including mobile apps) use OAuth's authorization code grant. This method works fine with many IdPs, including FusionAuth, but is not listed in this section because it is covered in the SPA and WebApp sections above. The only difference is that at the end of the OAuth workflow, the native application pulls the JWT and refresh tokens from the web-view.&lt;/p&gt;

</description>
      <category>auth</category>
      <category>spa</category>
      <category>login</category>
      <category>idp</category>
    </item>
    <item>
      <title>Hacktoberfest 2023 with FusionAuth</title>
      <dc:creator>FusionAuth</dc:creator>
      <pubDate>Wed, 04 Oct 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/fusionauth/hacktoberfest-2023-with-fusionauth-56g4</link>
      <guid>https://dev.to/fusionauth/hacktoberfest-2023-with-fusionauth-56g4</guid>
      <description>&lt;p&gt;We're excited to announce FusionAuth's participation in this year's Hacktoberfest! Hacktoberfest is a global event that takes place every October, during which developers are encouraged to contribute to open-source projects like FusionAuth. The goal is to foster a vibrant open-source community, celebrate shared knowledge, and make the world of coding more accessible to all. You can find other participating repositories by searching the &lt;a href="https://github.com/topics/hacktoberfest" rel="noopener noreferrer"&gt;hacktoberfest topic&lt;/a&gt; on github.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;The first step is to &lt;a href="https://hacktoberfest.com/register" rel="noopener noreferrer"&gt; register for Hacktoberfest&lt;/a&gt;. Once you've registered, any PRs submitted to FusionAuth will count towards your participation in the event!&lt;/p&gt;

&lt;h2&gt;
  
  
  Contributing
&lt;/h2&gt;

&lt;p&gt;If you haven't participated before make sure to read the &lt;a href="https://hacktoberfest.com/participation/%20" rel="noopener noreferrer"&gt; Hacktoberfest Participation Guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To see all of FusionAuth's issues in one place see the &lt;a href="https://github.com/search?q=user%3AFusionAuth+label%3Ahacktoberfest+state%3Aopen&amp;amp;type=Issues&amp;amp;ref=advsearch&amp;amp;l=&amp;amp;l="&gt;full issue search&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This year for the Hacktoberfest we choose to focus on all of our JavaScript repositories. I have added the tag &lt;code&gt;hacktoberfest&lt;/code&gt; to each one of the following repositories and even added an issue for simply updating the packages to their latest version. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/fusionauth/fusionauth-quickstart-javascript-angular-web"&gt;Angular&lt;/a&gt;- The Authorization Code grant using the Angular framework&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/FusionAuth/fusionauth-example-express-consents"&gt;Consents&lt;/a&gt;- Example using advanced registration forms and consents&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/FusionAuth/fusionauth-example-node-deeplink"&gt;Deeplinking&lt;/a&gt;- Example returning users to the same page they logged in on&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/fusionauth/fusionauth-example-device-grant"&gt;Device grant&lt;/a&gt;- An example of the Device Authorization grant&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/FusionAuth/fusionauth-example-express-api"&gt;Express API&lt;/a&gt;- Express api which uses the Cookie Access Token&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/fusionauth/fusionauth-example-family"&gt;Family management&lt;/a&gt;- Family management and consent creation&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/FusionAuth/fusionauth-example-node-sso"&gt;FusionAuth SSO&lt;/a&gt;- Example of SSO between two different custom applications&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/FusionAuth/fusionauth-example-gaming-device-grant"&gt;Gaming and device grant&lt;/a&gt;- Example using the Device Authorization grant to provide authentication to a game.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/fusionauth/fusionauth-example-gatsby"&gt;Gatsby OAuth&lt;/a&gt;- An example of using Gatsby with the Authorization Code grant and PKCE&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/FusionAuth/fusionauth-example-node-services-gateway-jwtauth"&gt;JWT Auth and a Microservices gateway&lt;/a&gt;- API gateway and microservices secured using JWT auth&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/fusionauth/fusionauth-example-javascript-jwt"&gt;Javascript JWT&lt;/a&gt;- JWT creation and decoding examples with javascript&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/FusionAuth/fusionauth-example-nextjs-magic-links"&gt;Magic links login&lt;/a&gt;- nextjs app which uses magic links for authentication&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/FusionAuth/fusionauth-example-node-services-gateway"&gt;Microservices gateway&lt;/a&gt;- API gateway and microservices&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/FusionAuth/fusionauth-example-node-multi-tenant"&gt;Multi-tenant application&lt;/a&gt;- Two nodejs applications in different tenants, living in different domains.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/FusionAuth/fusionauth-example-nextjs-single-sign-on"&gt;Next.js Single Sign-On&lt;/a&gt;- Single sign-on with Next.js and FusionAuth&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/fusionauth/fusionauth-example-node"&gt;Node OAuth&lt;/a&gt;- Login with the Authorization Code grant&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/fusionauth/fusionauth-example-react-native-0-71"&gt;React Native&lt;/a&gt;- The Authorization Code grant for a React Native mobile application&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/fusionauth/fusionauth-example-react-sdk"&gt;React with an Express backend&lt;/a&gt;- The Authorization Code grant using the React framework with the FusionAuth React SDK and an Express backend&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/fusionauth/fusionauth-quickstart-javascript-react-web"&gt;React with the hosted backend&lt;/a&gt;- The Authorization Code grant using the React framework with the FusionAuth React SDK and the hosted backend&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/FusionAuth/fusionauth-example-remix"&gt;Remix auth&lt;/a&gt;- Example using FusionAuth to provide auth for a Remix application&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/FusionAuth/fusionauth-example-express-twitter"&gt;Twitter login&lt;/a&gt;- Node/express app which uses Twitter for authentication&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/FusionAuth/fusionauth-example-user-actions-guide"&gt;User actions example&lt;/a&gt;- Corresponds to the user actions guide tutorial&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/fusionauth/fusionauth-quickstart-javascript-vue-web"&gt;Vue.js&lt;/a&gt;- The Authorization Code grant using the Vue.js framework&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>hacktoberfest</category>
    </item>
    <item>
      <title>How to set up an anonymous user flow</title>
      <dc:creator>FusionAuth</dc:creator>
      <pubDate>Mon, 02 Oct 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/fusionauth/how-to-set-up-an-anonymous-user-flow-1h58</link>
      <guid>https://dev.to/fusionauth/how-to-set-up-an-anonymous-user-flow-1h58</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gV6L_P2r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2g8xfqx2qibzybx6dyh0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gV6L_P2r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2g8xfqx2qibzybx6dyh0.png" alt="How to set up an anonymous user flow" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For many applications, a user is forced to register for application access. You want to know who the user is so you can provide them with individualized functionality and data.&lt;/p&gt;

&lt;p&gt;If your registration process requires an email or mobile phone number, registration allows you to market to your customers. This is great if you are pursuing a Product-led growth or freemium business model. Having contact information allows you to communicate with them directly, allowing you to remind them of the value of your application and driving re-engagement.&lt;/p&gt;

&lt;p&gt;But sometimes, you don't want any registration friction, even though you want the user to access customized functionality or save data on your system. Anonymous users can help with this. Such users don't have any credentials or personally identifiable data associated with their accounts. They do exist in your customer identity and access management (CIAM) system and can be treated like any other account in terms of profile data or reporting. &lt;/p&gt;

&lt;p&gt;FusionAuth doesn't support this concept using &lt;a href="https://fusionauth.io/docs/v1/tech/core-concepts/integration-points#hosted-login-pages"&gt;hosted login pages&lt;/a&gt;. The hosted login pages abide by the 80/20 rule. They cover 80% of the use cases for customer identity and access management.&lt;/p&gt;

&lt;p&gt;When the hosted login pages don't meet your needs, you can use the &lt;a href="https://fusionauth.io/docs/v1/tech/apis/"&gt;APIs&lt;/a&gt; to build your workflows. You can do this for anonymous users. Here's a &lt;a href="https://fusionauth.io/docs/v1/tech/guides/anonymous-user"&gt;guide to implement this custom registration flow&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;The rest of this blog post will look at some of the wrinkles of building out this progressive registration process, whether you use FusionAuth or any other system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Anonymous User Lifecycle
&lt;/h2&gt;

&lt;p&gt;Anonymous users have a more complex life cycle than the typical CIAM user. Here's a typical lifecycle.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A person visits your application. This person is called a visitor or unknown user and is most likely tracked by analytics or web stats logging software.&lt;/li&gt;
&lt;li&gt;The visitor may take multiple actions such as viewing pages.&lt;/li&gt;
&lt;li&gt;The person takes a certain action in your application that requires the creation of a profile.&lt;/li&gt;
&lt;li&gt;An anonymous account is created to capture profile data. This is also known as a stub or shadow account.&lt;/li&gt;
&lt;li&gt;The person continues to take additional actions in the application. Some of these may trigger updates to the anonymous profile, others may not.&lt;/li&gt;
&lt;li&gt;At some time, the user registers for a conventional account. They may be prompted to do so based on activity, such as access to advanced functionality or an action that impacts the real world. Or they may choose to register.&lt;/li&gt;
&lt;li&gt;The person registers and the account converts to a normal user account, including all extant profile data.&lt;/li&gt;
&lt;li&gt;The person receives an email or text to set up their account.&lt;/li&gt;
&lt;li&gt;The person sets up their credentials, including password and/or additional factors.&lt;/li&gt;
&lt;li&gt;The person continues on their merry way, interacting with the application.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The application benefits by having a lower time to value. The user benefits because they have access to functionality or preferences before they register, as well as retaining access to any such data after registration.&lt;/p&gt;

&lt;p&gt;As mentioned above, this is an example of progressive registration, with some profile data gathering taking place while the identity is unknown.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Anonymous Users Make Sense
&lt;/h2&gt;

&lt;p&gt;There are two broad scenarios where anonymous users make sense. &lt;/p&gt;

&lt;p&gt;First, if you want to serve personalized content or recommendations to a user who has yet to identify themself.&lt;/p&gt;

&lt;p&gt;You might do this to increase the usefulness of your site. For example, for an  e-commerce site, you might allow the user to "favorite" items they are interested in. You could then surface related items, or items that other similar users found interesting. Another example might be an online game. Users might want to tweak how their character looks without bothering to register, and such tweaking might drive more gameplay.&lt;/p&gt;

&lt;p&gt;Second, if you want a user to have provided information or preferences available after registration.&lt;/p&gt;

&lt;p&gt;You might do this if you want to allow users to experience application functionality without the friction of signing up. For instance, a diagramming application might allow anonymous users to create diagrams. Users would welcome having their saved diagrams available after they have registered. In the above  e-commerce example, the favorited items should be available for perusal (and purchase!) after user registration.&lt;/p&gt;

&lt;p&gt;Anonymous accounts can be helpful across a wide variety of business domains, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; E-commerce sites with a shopping cart&lt;/li&gt;
&lt;li&gt;B2B applications where users can create software artifacts&lt;/li&gt;
&lt;li&gt;games&lt;/li&gt;
&lt;li&gt;high value research applications, such as real estate search sites &lt;/li&gt;
&lt;li&gt;news and content sites where personalization can drive engagement&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, anonymous accounts aren't always a good option. They don't make sense:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;for applications where anonymous users don't make sense, such as an email or banking application&lt;/li&gt;
&lt;li&gt;if the profile data of the anonymous user is not valuable to the application or the user&lt;/li&gt;
&lt;li&gt;for applications where you must be able to contact all users&lt;/li&gt;
&lt;li&gt;if the profile data is highly sensitive, such as medical information&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementation Subtleties
&lt;/h2&gt;

&lt;p&gt;There are some implementation concerns you should consider when building a system with anonymous users.&lt;/p&gt;

&lt;h3&gt;
  
  
  Marking Accounts as Anonymous
&lt;/h3&gt;

&lt;p&gt;Make sure you have some way to identify anonymous users as such. In FusionAuth, you might use the &lt;code&gt;user.data&lt;/code&gt; field. Below is a screenshot of an anonymous user in the admin UI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8j3i-MYb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/img/blogs/anonymous-user/anonymous-user-in-admin-screen.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8j3i-MYb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/img/blogs/anonymous-user/anonymous-user-in-admin-screen.png" alt="An anonymous user account in the FusionAuth admin UI." width="800" height="745"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Marking users in this way allows you to run analytics to understand user behavior. It also lets you remove inactive anonymous accounts.&lt;/p&gt;

&lt;p&gt;The string &lt;code&gt;DNUXUS8WIUXRGHQSNALTECZGD8IYZ7LN0X09RTTX2G9WMVFWJ6CF3T7HMCJWV3SF&lt;/code&gt; is a random username, since FusionAuth requires all users to have either a username or an email address. &lt;/p&gt;

&lt;h3&gt;
  
  
  Storing The Anonymous User's Identity
&lt;/h3&gt;

&lt;p&gt;After you create an anonymous profile, you need to associate the person with that profile. With a web application, you can set a persistent cookie to maintain this association. The value of the cookie is typically a synthetic user Id, which does not identify the user outside of your system. A UUID is a good choice.&lt;/p&gt;

&lt;p&gt;You can store the Id in the following ways inside the cookie:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A plaintext value is easiest, but a malicious client can tweak the user Id to explore different users' saved data.&lt;/li&gt;
&lt;li&gt;A signed token, such as a JWT. Checking the signature on every request costs some computational power, but avoids malicious actors probing other user Ids.&lt;/li&gt;
&lt;li&gt;An encrypted, URL safe value. This is typically overkill for an opaque user Id, but if your user Id might leak information, such as the size of your user base because it is an integer value, then encryption might work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This cookie can be stored as an HTTPOnly, Secure cookie since only your server-side code will be examining it. Each time the cookie is presented, the server-side code can decode it, and then update the anonymous account profile if needed.&lt;/p&gt;

&lt;p&gt;Here's an example of code that sets a JWT with a user Id, using the &lt;a href="https://fusionauth.io/docs/v1/tech/apis/jwt#vend-a-jwt"&gt;FusionAuth JWT Vend API&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    # create a JWT, good for a year
    jwt_ttl=60*60*24*365
    jwt={
      'claims': {
        'userId': user_id
      },
      'keyId': env.get("SIGNING_KEY_ID"),
      'timeToLiveInSeconds': jwt_ttl
    }
    response = client.vend_jwt(jwt).success_response
    token=response['token']
    resp = make_response(render_template("video.html"))

    # set the cookie
    resp.set_cookie(ANON_JWT_COOKIE_NAME, token, max_age=jwt_ttl, httponly=True, samesite="Lax")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because you are storing information on the device, if a person accesses your site from a different browser or device, you have no way of reconciling them. This is also true if the user removes the cookie or the cookie expires. These are limitations of cookies, so there's no way around it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Converting Accounts
&lt;/h3&gt;

&lt;p&gt;When you convert an account, you associate the user Id stored in the cookie and a real-world user identifier such as an email address or a mobile phone number. Update the anonymous account with this information, which means it is no longer anonymous. Then send a "set up your password" request or other method of setting up credentials.&lt;/p&gt;

&lt;p&gt;Here's an example of code that does this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  # if they have a cookie, look up the user and convert them and send a password reset
    if request.method == 'POST':
      user_id = get_anon_user_id_from_cookie()
      if user_id is None:
        print("couldn't find user")
        message["message"] = "Couldn't find your user id."
        return render_template("register.html", message=message)

      # correct the email address using patch if the email doesn't already exist
      email_param = request.form["email"]

      user = client.retrieve_user_by_email(email_param).success_response
      message["message"] = "Please check your email to set your password."

      # if we already have the user in our system, fail silently. depending on your use case, you may want to sent the forgot password email, or display an error message
      if user is None:
        patch_data = {
          'user': {
            'email': email_param
          }
        }
        patch_response = client.patch_user(user_id, patch_data).success_response

        forgot_password_data = {
          'loginId': email_param,
          'state': { 'anon_user': 'true' }
        }
        trigger_email_response = client.forgot_password(forgot_password_data)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Verifying Accounts
&lt;/h3&gt;

&lt;p&gt;When converting an account from an anonymous account to a regular one, make sure you verify the user's ownership of the email address (or phone number) they provide. If you instead let someone provide an email address and password on the conversion page, anyone with device access would control the resulting profile.&lt;/p&gt;

&lt;p&gt;While that may be acceptable when an unknown user registers, where there is no anonymous user data, avoid letting someone "take over" an anonymous profile.&lt;/p&gt;

&lt;p&gt;One easy way to verify ownership is to send the password reset email or text after the user provides an email address or mobile phone number. At that point, you know they "own" it.&lt;/p&gt;

&lt;p&gt;Then you can update the associated profile to remove anonymous account indicators. Below you can see the code to do this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@app.route("/webhook", methods=['POST'])
def webhook():
  # look up the user by id. If they are not an anonymous user return 204 directly, otherwise update their anonymous user status to be false and return 204
  # looking for email user login event because email verified is only fired on explicit email verification
  if request.method == 'POST':
    webhookjson = request.json
    event_type = webhookjson['event']['type']
    is_anon_user = webhookjson['event']['user'] and webhookjson['event']['user']['data'] and webhookjson['event']['user']['data']['anonymousUser']
    if event_type == 'user.login.success' and is_anon_user:
      user_id = webhookjson['event']['user']['id']
      patch_data = {
        'user': {
          'username': '',
          'data' : {
            'anonymousUser':False
          }
        }
      }
      patch_response = client.patch_user(user_id, patch_data).success_response

  return '', 204
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In FusionAuth, the easiest way to do this is via a webhook, but different systems have different mechanisms. The important point is to leave the profile untouched until ownership is proven.&lt;/p&gt;

&lt;h3&gt;
  
  
  Culling Accounts
&lt;/h3&gt;

&lt;p&gt;At some point, clear out old anonymous accounts that have never converted to regular user accounts. Do this by querying the update timestamp of each anonymous account. Then, determine which untouched accounts are old enough to delete.&lt;/p&gt;

&lt;p&gt;Synchronize this with the lifetime of the cookie containing the user Id. If the cookie is good for a month, you can clear out accounts that have not been updated for 40 days, because the user would never be able to successfully convert their anonymous account after the cookie is gone.&lt;/p&gt;

&lt;p&gt;This reaping process can be run periodically by a scheduled job.&lt;/p&gt;

&lt;h3&gt;
  
  
  Privacy Concerns
&lt;/h3&gt;

&lt;p&gt;Ensure you abide by all rules for jurisdictions where your users live. In particular, make sure you don't collect &lt;a href="https://commission.europa.eu/law/law-topic/data-protection/reform/what-personal-data_en"&gt;any personal data&lt;/a&gt; unless you have the processes in place to abide by the GDPR.&lt;/p&gt;

&lt;p&gt;Personal data is defined as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;any information that relates to an identified or identifiable living individual. Different pieces of information, which collected together can lead to the identification of a particular person, also constitute personal data.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Billing Concerns
&lt;/h3&gt;

&lt;p&gt;While the creation of anonymous accounts is unlikely to impact the system performance of an identity provider, these profiles may impact your bill. If your identity provider charges based on active users, you may be charged for these accounts. Before implementing this flow, make sure you understand what a large number of user accounts does to your pricing.&lt;/p&gt;

&lt;p&gt;For example, if you are using FusionAuth to implement this workflow, each anonymous account will be counted as an MAU for the month it is created, but not in subsequent months. &lt;/p&gt;

&lt;h2&gt;
  
  
  Why Not Just Use JavaScript
&lt;/h2&gt;

&lt;p&gt;You can definitely track anonymous actions with JavaScript, with a tool like Google Analytics. However, at some point, you will need to convert the profile to a server-side account with real credentials, so it may be easier to create it on the server side initially.&lt;/p&gt;

&lt;p&gt;In addition, if you want to have a single view of your user base, having all users in one data store will be easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn More
&lt;/h2&gt;

&lt;p&gt;If you want to learn more about the anonymous user workflow, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read &lt;a href="https://fusionauth.io/docs/v1/tech/guides/anonymous-user"&gt;the anonymous user guide&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Run and tweak &lt;a href="https://github.com/FusionAuth/fusionauth-example-anonymous-user"&gt;an example anonymous user application&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Read &lt;a href="https://fusionauth.io/articles/ciam/unlocking-growth-low-friction-signup-process"&gt;"Unlocking Growth: Why A Low Friction User Signup Process Is Crucial For Your Business"&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>anonymousaccounts</category>
      <category>customloginworkflows</category>
      <category>jwts</category>
      <category>registration</category>
    </item>
    <item>
      <title>Get More Value Out of FusionAuth Using the APIs for User Maintenance</title>
      <dc:creator>FusionAuth</dc:creator>
      <pubDate>Fri, 01 Sep 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/fusionauth/get-more-value-out-of-fusionauth-using-the-apis-for-user-maintenance-110n</link>
      <guid>https://dev.to/fusionauth/get-more-value-out-of-fusionauth-using-the-apis-for-user-maintenance-110n</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7xpZdxI8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gjyj4rrsmh9mgh109m3h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7xpZdxI8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gjyj4rrsmh9mgh109m3h.png" alt="Get More Out of FusionAuth Using APIs for User Maintenance" width="800" height="420"&gt;&lt;/a&gt;&lt;br&gt;
So, you have just set up FusionAuth and are excited to take your new &lt;a href="https://fusionauth.io/articles/ciam/"&gt;customer identity and access management&lt;/a&gt; platform out for a spin. You spend some time setting up your Users, Applications, Tenants, etc. in the robust admin interface provided. Things are looking great. You have integrated your applications and are humming along. Now comes a real test, user maintenance.&lt;/p&gt;
&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;“A new user with extra pickles, please.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Customizing the order for your favorite food can make a good meal better. Customizing your end-users' experience with user maintenance can make their experience with your application even better.&lt;/p&gt;

&lt;p&gt;For any &lt;a href="https://fusionauth.io/articles/security/steps-secure-your-authentication-system"&gt;secure application&lt;/a&gt;, user maintenance is a must. As a developer, you can often overlook the time and effort it takes to maintain the user's access and permissions for the shiny new application you created. In an ideal world, you do not want to be the ones to maintain the users. You want to give the task of user maintenance to the power users of the applications by making them application administrators. While those power users may be great at using the application, you don’t necessarily want to make them expert users of the FusionAuth admin interface. Well, we at FusionAuth would think it would be great if everyone was a master with it, but you may not share that same vision.&lt;/p&gt;

&lt;p&gt;Imagine you have an application that controls a machine that applies the toppings to a burger. Custom Burger, the popular new burger joint just bought your application. The tech-savvy manager, Sally Power-User, has been given admin rights. Sally just hired Joe Limited-Access to work the night shift. She now needs to add Joe as a user of your application. She needs to ensure Joe can add pickles to a burger order but make sure he does not have access to apply the famous Flaming Carolina Reaper Sauce until he goes through training. Your application will have to support this.&lt;/p&gt;

&lt;p&gt;You can harness the full power of FusionAuth in your application, hand off the user maintenance to the power users, and make it seamless for them. The application will need to ensure that Sally Power-User enters the correct information (&lt;strong&gt;Validation&lt;/strong&gt;), guide her through setting up the new Joe Limited-Access user correctly (&lt;strong&gt;Workflow&lt;/strong&gt;), and you want to make the process feel like it is part of your application (&lt;strong&gt;Branding&lt;/strong&gt;). You can accomplish all these through the use of the FusionAuth APIs.&lt;/p&gt;

&lt;p&gt;Newer developers should be aware the examples below are written with the assumption that you are familiar with how to make REST calls using the &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclient?view=net-7.0"&gt;HttpClient&lt;/a&gt; in C#, the use of &lt;a href="https://learn.microsoft.com/en-us/dotnet/csharp/asynchronous-programming/"&gt;asynchronous&lt;/a&gt; calls and Windows Forms applications. In order for the sample application to run you must have a working &lt;a href="https://dev.to/docs/v1/tech/5-minute-setup-guide"&gt;FusionAuth server&lt;/a&gt;. Even if you are not totally familiar with these concepts, you will likely be able to follow the code snippets with general programming knowledge. If you need a refresher on some of these topics, there are some links at the end.&lt;/p&gt;

&lt;p&gt;If you are only interested in jumping into the code, it can be found &lt;a href="https://github.com/FusionAuth/fusionauth-example-dotnet-windowsform-api"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Custom Validation With FusionAuth APIs
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;“With great power, comes great responsibility!”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;One of FusionAuth’s strengths is its flexibility. However, with the flexibility comes some complexity. To create a user in the FusionAuth admin user interface, you only need two pieces of information. You will need to supply either the username or the email in addition to a password. (If you are using multiple tenants, you will need the tenant ID as well.) The FusionAuth admin user interface gives you other optional fields to fill in, however none are required. When using the &lt;a href="https://fusionauth.io/docs/v1/tech/apis/users#create-a-user"&gt;Create a User API&lt;/a&gt;, only the username or email in addition to the password is still required but there are also over 30 additional request parameters available for customization. Creating a custom admin interface around the APIs will not only allow you to choose which of the username or email fields to use, but also what other meta-data is appropriate and required for your application. Below is sample code for creating a user using the FusionAuth API.&lt;/p&gt;
&lt;h3&gt;
  
  
  Setting Up The User Object
&lt;/h3&gt;

&lt;p&gt;First, you need to create a few objects to hold some values. By constructing the classes and decorating properties with the proper attributes, you can still use the strongly typed objects and standard naming conventions in your C# application while also using the JSON Serializer to easily format the request body when it is time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using Newtonsoft.Json;

namespace FusionDemoAPI.Helper
{
  public class User
  {
    [JsonProperty(PropertyName = "user")]
    public UserProperties UserProperties;
  }

  public class UserProperties
  {
    [JsonProperty(PropertyName = "firstName")]
    public string FirstName;
    [JsonProperty(PropertyName = "lastName")]
    public string LastName;
    [JsonProperty(PropertyName = "email")]
    public string Email;
    [JsonProperty(PropertyName = "password")]
    public string Password;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Taking Input From The User
&lt;/h3&gt;

&lt;p&gt;Next, you need to take the input from the user and assign them to the values in your User object. In this case, you are performing those actions on a click event from the &lt;code&gt;Create User&lt;/code&gt; button on a &lt;a href="https://learn.microsoft.com/en-us/visualstudio/ide/create-csharp-winform-visual-studio?view=vs-2022"&gt;Windows Form&lt;/a&gt;. Pictured below is a screen shot of the interface for the sample application. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--69goAwR---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vb3ctewzao61ke75d18o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--69goAwR---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vb3ctewzao61ke75d18o.png" alt="The Windows demo front end." width="800" height="501"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also take this chance to validate any information deemed relevant to your application. The logic in the &lt;code&gt;IsUserValid&lt;/code&gt; function can be edited to suit your needs. In this sample application it simply returns true. I know, not very creative, but useful in the demo. You can also validate age, location or anything else you choose. Once the validation is successful, you will then pass the user object to the method that will submit your request to the FusionAuth server. Validating input like this will ensure Sally Power-User enters the correct information for the system every time she adds a new employee.&lt;/p&gt;

&lt;p&gt;It is important to note that the &lt;code&gt;FusionAuthClient&lt;/code&gt; that has been created for this applications handles the setting of the &lt;a href="https://fusionauth.io/docs/v1/tech/apis/api-keys#overview"&gt;API Key&lt;/a&gt; and location of the FusionAuth server. These settings are stored in the &lt;code&gt;App.settings&lt;/code&gt; file for the project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    private async void btnCreateUser_Click(object sender, EventArgs e)
    {
      //FusionAuthClient is a class that contains the logic to call the FusionAuth APIs
      var faClient = new FusionAuthClient();

      UserProperties userProperties = new UserProperties()
      {
        Email = txtEmail.Text,
        FirstName = txtFirstName.Text,
        LastName = txtLastName.Text,
        Password = txtPassword.Text
        //add additional properties here
      };

      User userToCreate = new User()
      {
        UserProperties = userProperties
      };

      //perform custom validation logic in the IsUserValid method
      if (IsUserValid(userToCreate))
      {
        ReturnValue userCreatedReturnValue = await faClient.CreateUser(userToCreate);
        if (userCreatedReturnValue.success == true)
        {
          LogResults($"User created with ID: {userCreatedReturnValue.result}");
          PopulateComboBox(cmbUsersToDelete, PopulateType.Users);
        }
        else
        {
          LogResults($"User creation failed. {userCreatedReturnValue.result}");
        }
      }
      else
      {
        LogResults($"User data provided is invalid");
      }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Creating The User
&lt;/h3&gt;

&lt;p&gt;Because you decorated your User objects correctly using the JSONProperty attribute, you can use the JSON Serializer to serialize the object with the &lt;code&gt;JsonConvert.SerializeObject&lt;/code&gt; method. You also need to encode it properly before you submit it. Once that is complete, you can submit the request to the FusionAuth server. You will do so here using the async pattern so as to not hold up the processing for a request that may take some time or give the application an unresponsive feel. Once you receive the return values, you can interrogate them and act accordingly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    public async Task&amp;lt;ReturnValue&amp;gt; CreateUser(User userToCreate)
    {
      //returns HttpClient with correct setting for instance
      HttpClient httpClient = GetClient();

      //initialize the return value 
      ReturnValue returnVal = new ReturnValue()
      {
        success = false
      };

      try
      {
        //set the endpoint for creating a user
        string apiURL = $"/api/user";

        var payload = JsonConvert.SerializeObject(userToCreate);
        var content = new StringContent(payload, Encoding.UTF8, "application/json");

        HttpResponseMessage response = await httpClient.PostAsync($"{FUSIONAUTH_HOST}{apiURL}", content);

        if (response.IsSuccessStatusCode)
        {

          string responseBody = await response.Content.ReadAsStringAsync();
          JObject result = JObject.Parse(responseBody);
          returnVal.success = true;
          //assign the newly created user id to the result
          returnVal.result = result["user"]["id"].ToString();
        }

      }
      catch (Exception ex)
      {
        Console.WriteLine($"There was an error in the request {ex.Message}");
        returnVal.result = ex.Message;
      }

      return returnVal;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  User Workflow With FusionAuth APIs
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;“Amateurs do it till they get it right. Professionals do it until they can not get it wrong.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You may have originally set up the users manually in the FusionAuth admin user interface and that is fine to get started. However, the more steps and requirements you have for creating a user, the more likely something will be missed. There can be several steps required to set up a user correctly such as making sure they belong to the correct group(s). While you may be infallible as a developer and get it right every time, wink wink, most likely your users will not.&lt;/p&gt;

&lt;p&gt;You can use the FusionAuth APIs to ensure the user is added to the correct group or groups so their permissions will be set properly. After the user is created, you can take this opportunity to automatically assign the user to a specific group or present an admin interface to the administrator that will guide them in selecting the proper group(s). For example, you can ensure Sally Power-User cannot add Joe Limited-Access to the Flaming Carolina Reaper Sauce Appliers on the day she creates him as a user because you know he has not had time to go through the training.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up The Group Object
&lt;/h3&gt;

&lt;p&gt;Once again, you will need to create a few objects to help us organize your groups. The &lt;a href="https://fusionauth.io/docs/v1/tech/apis/groups#add-users-to-a-group"&gt;Add Users to a Group API&lt;/a&gt; call you are using requires a collection of groups that each contain an array of user information. In this case, you will only be using the user Id for the new GroupUser information.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using Newtonsoft.Json;
using System.Collections.Generic;

namespace FusionDemoAPI.Helper
{
  public class Group
  {
    public string ID;
    public List&amp;lt;GroupUser&amp;gt; Users;
  }

  public class GroupUser
  {
    [JsonProperty(PropertyName = "userId")]
    public string UserID;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Taking Input From The User
&lt;/h3&gt;

&lt;p&gt;As with creating the user, you need to take the input from the application and assign the values to your Group objects. Again, the &lt;code&gt;IsGroupValid&lt;/code&gt; function simply returns true for the sample application but you can also validate any data you want before actually adding the user to the group. After you are satisfied the user should be added, you can submit the information to the method that will submit your request to the FusionAuth server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    private async void btnAddUserToGroup_Click(object sender, EventArgs e)
    {
      //FusionAuthClient is a class that contains the logic to call  the FusionAuth APIs
      var faClient = new FusionAuthClient();
      //Get the selected values from the dropdowns
      var userIdToAdd = (string)cmbUsersToAddToGroup.SelectedValue;
      var groupIdToAdd = (string)cmbGroups.SelectedValue;

      if (userIdToAdd != null &amp;amp;&amp;amp; groupIdToAdd != null)
      {
        List&amp;lt;GroupUser&amp;gt; users = new List&amp;lt;GroupUser&amp;gt;()
                {
                    new GroupUser()
                    {
                        UserID = userIdToAdd
                    }
                };

        Group group = new Group();
        group.ID = groupIdToAdd;
        group.Users = users;

        List&amp;lt;Group&amp;gt; groups = new List&amp;lt;Group&amp;gt;();
        groups.Add(group);

        //perform custom validation logic here
        if (IsGroupValid(group))
        {
          ReturnValue addUserToGroupReturnValue = await faClient.AddUserToGroup(groups);
          if (addUserToGroupReturnValue.success == true)
          {
            LogResults($"User {(string)cmbUsersToAddToGroup.Text} has been added to the group: {(string)cmbGroups.Text}");
          }
          else
          {
            LogResults($"Adding the user to the group has failed. {addUserToGroupReturnValue.result}");
          }
        }
        else
        {
          LogResults($"User and/or group data provided is invalid");
        }
      }
      else
      {
        LogResults($"No group or user selected.  Populate Users and Groups.");
      }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding The User To The Group
&lt;/h3&gt;

&lt;p&gt;Because the JSON format expected in the request body is not readily serializable given the Group objects you have created, you will have to perform a little wizardry to manipulate the Group objects. While this does not have to do with FusionAuth specifically, the code has been abstracted in the &lt;code&gt;FormatGroupUserJSON&lt;/code&gt; function and can be found &lt;a href="https://github.com/FusionAuth/fusionauth-example-dotnet-windowsform-api/blob/35307a11e43caa098d3366be58b07cf0452b6488/sourcecode/FusionDemoAPI/FusionAuthClient.cs#L267-L295"&gt;here&lt;/a&gt; if you are interested. Once the API call has returned, you can retrieve whichever values you see as relevant and pass it back in the result object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    public async Task&amp;lt;ReturnValue&amp;gt; AddUserToGroup(List&amp;lt;Group&amp;gt; groups)
    {
      //returns HttpClient with correct setting for instance
      HttpClient httpClient = GetClient();

      //initialize the return value 
      ReturnValue returnVal = new ReturnValue()
      {
        success = false
      };

      try
      {
        //set the endpoint for creating a user
        string apiURL = $"/api/group/member";

        var payload = FormatGroupUserJSON(groups);
        var content = new StringContent(payload, Encoding.UTF8, "application/json");

        HttpResponseMessage response = await httpClient.PostAsync($"{FUSIONAUTH_HOST}{apiURL}", content);

        if (response.IsSuccessStatusCode)
        {

          string responseBody = await response.Content.ReadAsStringAsync();
          JObject result = JObject.Parse(responseBody);
          returnVal.success = true;
          returnVal.result = $"Member ID for added user: {result["members"].First().First()[0]["id"]}";
        }
        else
        {
          returnVal.result = $"Adding user to the group failed.\nPayload\n{payload}\n{response}";
        }

      }
      catch (Exception ex)
      {
        Console.WriteLine($"There was an error in the request {ex.Message}");
        returnVal.result = ex.Message;
      }


      return returnVal;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Branding Your User Management With FusionAuth
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;“Design is the silent ambassador of your brand.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;One of the best parts about using the APIs to allow application admins to manage their own users is they never have to leave your application. Users are accustomed to things such as Single Page Applications or at least applications that have a consistent look and feel. Depending on the use case, a user may feel uncomfortable switching to the FusionAuth admin interface to manage users. While FusionAuth has a well designed and functional admin interface, the look and feel will likely be different than your application. By using the APIs you can still use all of your own style sheets and design principles.&lt;/p&gt;

&lt;p&gt;You may ask yourself, “If I create an admin end for user management in my application, shouldn’t I just create the authentication and authorization framework as well?” The answer to that question is a resounding “No!” The security, power and flexibility FusionAuth gives you has taken years to build. You should focus on providing the unique business value your application provides versus reinventing the authentication wheel. The best part is that you can leverage our investment by creating a simple &lt;a href="https://fusionauth.io/articles/ciam/"&gt;customer identity and access management&lt;/a&gt; interface around the security and power of FusionAuth. You get the best of both worlds.&lt;/p&gt;

&lt;p&gt;You don’t even have to tell your users you are using FusionAuth. It’s okay, we don’t mind. We want to make you look good, help you secure your users, and let you focus on building the features your users want.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BrQMwe62--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/img/blogs/get-more-value/one-does-not-simply.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BrQMwe62--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/img/blogs/get-more-value/one-does-not-simply.png" alt="One does not simply implement user access management." width="651" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;It is important to note that as an alternative, FusionAuth does allow the creation of &lt;a href="https://dev.to/docs/v1/tech/core-concepts/tenants#form-settings"&gt;custom forms&lt;/a&gt; in the admin user interface. This solution is only available for paid plans, may not support the workflow you are trying to accomplish and would not work if you did not want to give users access to the FusionAuth admin interface.&lt;/p&gt;

&lt;p&gt;These are a few examples of how to use the FusionAuth APIs to get more value out of FusionAuth. Please take some time to explore the &lt;a href="https://dev.to/docs/v1/tech/apis/"&gt;FusionAuth API documentation&lt;/a&gt; and get some more ideas of ways to use them to better serve your development. For instance, you have used the APIs to create a user, but you can use similar APIs to delete users or remove their application access. For example, you can monitor an external application and remove the user from FusionAuth on a given event.&lt;br&gt;
 By integrating the FusionAuth APIs not only can you automate the validation process, setup users, and make it all look like your own, but you can add almost any ability within FusionAuth to your application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;If you enjoyed this article, please check out some of the other links and resources about FusionAuth.&lt;/p&gt;

&lt;h3&gt;
  
  
  FusionAuth APIs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://fusionauth.io/docs/v1/tech/apis/"&gt;General API Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fusionauth.io/docs/v1/tech/apis/users#create-a-user"&gt;Create a User&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fusionauth.io/docs/v1/tech/apis/users#delete-a-user"&gt;Delete a User&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fusionauth.io/docs/v1/tech/apis/groups#add-users-to-a-group"&gt;Add Users to a Group&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  FusionAuth Server Setup
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://fusionauth.io/docs/v1/tech/5-minute-setup-guide"&gt;5-Minute Setup Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Sample Application Source
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/FusionAuth/fusionauth-example-dotnet-windowsform-api"&gt;FusionAuth API Demo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  General
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclient?view=net-7.0"&gt;HttpClient&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/csharp/asynchronous-programming/"&gt;Asynchronous programming with async and await&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>api</category>
      <category>usermaintenance</category>
      <category>windows</category>
      <category>forms</category>
    </item>
    <item>
      <title>From ALB to Caddy - Our Wandering Path to Supporting Thousands of Domain Names</title>
      <dc:creator>FusionAuth</dc:creator>
      <pubDate>Thu, 24 Aug 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/fusionauth/from-alb-to-caddy-our-wandering-path-to-supporting-thousands-of-domain-names-3gmj</link>
      <guid>https://dev.to/fusionauth/from-alb-to-caddy-our-wandering-path-to-supporting-thousands-of-domain-names-3gmj</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6MAUwukq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1quci56q6fy1imz3tfsd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6MAUwukq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1quci56q6fy1imz3tfsd.png" alt="How We Built Unlimited Custom Domains" width="800" height="420"&gt;&lt;/a&gt;&lt;br&gt;
In the world of cloud services, offering 'unlimited' often feels like a stretch. But we've done just that. We recently unveiled support for unlimited custom domains in FusionAuth Cloud. This marked a significant milestone in our journey and changed the game for our customers.  Dive in as we unpack the architectural wizardry behind this transformative feature.&lt;/p&gt;

&lt;p&gt;When customers use our FusionAuth Cloud managed hosting service, they can configure one or more custom domain names for their authentication server.&lt;/p&gt;

&lt;p&gt;For example, a hosted deployment located at piedpiper.fusionauth.io could also be accessed at auth.piedpiper.com or id.piedpiper.com. This allows customers to keep their users on the same domain and maintain their branding throughout authentication flows.&lt;/p&gt;

&lt;p&gt;For most companies, one or two custom domains is sufficient. However some business models have thousands of domain names, representing different applications or customers. In an ideal world, the same authentication source would serve all of these domain names..&lt;/p&gt;

&lt;p&gt;FusionAuth supports &lt;a href="https://dev.to/docs/v1/tech/core-concepts/tenants"&gt;multiple tenants&lt;/a&gt; and applications, so this shouldn't be a problem, right?&lt;/p&gt;

&lt;p&gt;Right?&lt;/p&gt;

&lt;p&gt;Correct! This is not an issue for FusionAuth as a product!&lt;/p&gt;

&lt;p&gt;But things get a bit more complicated inside of &lt;a href="https://dev.to/platform/fusionauth-cloud"&gt;FusionAuth Cloud&lt;/a&gt;, our managed hosting option, which runs on Amazon Web Services (AWS).&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works Today
&lt;/h2&gt;

&lt;p&gt;Let's take a look at the architecture of FusionAuth Cloud, which includes both FusionAuth the product and surrounding infrastructure, called a deployment.&lt;/p&gt;

&lt;p&gt;Internet traffic flowing into FusionAuth Cloud first arrives via a Global Accelerator and is then forwarded to an &lt;a href="https://aws.amazon.com/elasticloadbalancing/application-load-balancer"&gt;Application Load Balancer&lt;/a&gt; (ALB) for routing. The ALB is responsible for handling the TLS handshake, the routing of traffic to customer deployments, as well as performing distributed denial of service (DDoS) protection and web application firewall (WAF) filtering. This ALB must be configured with a TLS certificate and a routing rule for each of our customer's domains.&lt;/p&gt;

&lt;p&gt;However, AWS imposes limitations on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The number of Subject Alternative Names (hostnames) per certificate&lt;/li&gt;
&lt;li&gt;  The number of certificates associated with an ALB&lt;/li&gt;
&lt;li&gt;  The number of hostname routing rules associated with an ALB&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes it impossible to use a single ALB to handle the traffic for all of our FusionAuth Cloud customers in a given region. In order to work around these limitations, we have provisioned additional ALBs and Global Accelerators. This also meant we imposed a limit on customers: they may only have four custom domains per deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's This Unlimited Domains Stuff Anyway?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.toblog/introducing-unlimited-custom-domains-for-fusionauth-cloud"&gt;Unlimited Domains&lt;/a&gt; is a new feature of FusionAuth Cloud that utilizes a modern edge infrastructure, providing dynamic TLS certificate provisioning and has no limits on the number of custom domains for a given deployment&lt;sup&gt;1&lt;/sup&gt;. It is currently an option available to select use cases for customers using High-Availability FusionAuth Cloud deployments.&lt;/p&gt;

&lt;p&gt;&lt;sup&gt;1&lt;/sup&gt; Nothing is truly infinite, but we have your use-case covered!&lt;/p&gt;

&lt;h2&gt;
  
  
  Coming Up With An Alternative
&lt;/h2&gt;

&lt;p&gt;Conceptually, the problem we were looking at is simple: We need to replicate the functionality of AWS's ALB, but without the limitations. Effectively, this should be implemented as a reverse-proxy that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Is highly-available across multiple &lt;a href="https://aws.amazon.com/about-aws/global-infrastructure/regions_az/"&gt;AWS Availability Zones&lt;/a&gt; (AZs)&lt;/li&gt;
&lt;li&gt;  Is horizontally scalable and can handle load as we grow&lt;/li&gt;
&lt;li&gt;  Can support dynamic management of TLS certificates without downtime&lt;/li&gt;
&lt;li&gt;  Has no limits on the number of hostnames it can route&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We decided to use AWS's Elastic Container Service (ECS) as our foundation, since it is fully managed and can automatically scale instances across AZs.&lt;/p&gt;

&lt;p&gt;For the reverse proxy, either HAProxy or nginx worked, but we needed to determine how we could reconfigure them at runtime to automatically provision certificates as customers added domain names. We spent some time researching their respective APIs to see how they would fit into the FusionAuth Cloud management infrastructure.&lt;/p&gt;

&lt;p&gt;During this research we stumbled upon &lt;a href="https://caddyserver.com/"&gt;Caddy&lt;/a&gt;, a software project that seemed to fit perfectly with our needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  It natively supports ACME, the certificate provisioning protocol used by LetsEncrypt.&lt;/li&gt;
&lt;li&gt;  It is happy running in a container.&lt;/li&gt;
&lt;li&gt;  It has an API for dynamic configuration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since Caddy was a new kid on the block, it required a more thorough investigation than the battle-tested incumbents.&lt;/p&gt;

&lt;p&gt;We set up a simulation environment to run it through its paces. Specifically, we wanted to ensure that when it was loaded up with 100k certificates, each with a unique hostname, it was able to perform TLS termination and route requests with throughput comparable to an ALB.&lt;/p&gt;

&lt;p&gt;We found that with minimal resources allocated to the container, there was no increase in request processing time as the number of installed certificates grew. We felt confident enough in Caddy to move forward with integrating it into a test environment which mirrored our production infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building It Out
&lt;/h2&gt;

&lt;p&gt;To avoid disruptions to our existing cloud deployments, we decided to build the new infrastructure in parallel with the existing systems.&lt;/p&gt;

&lt;p&gt;The new design consisted of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  A multi-AZ ECS cluster of Caddy instances running on Fargate. This cluster would manage certificates, terminate TLS, and forward requests back to each customer deployment.&lt;/li&gt;
&lt;li&gt;  An EFS volume for Caddy to store certificates. Sometimes you just need a filesystem.&lt;/li&gt;
&lt;li&gt;  A Network Load Balancer (NLB) to distribute traffic across the Caddy instances.&lt;/li&gt;
&lt;li&gt;  A Global Accelerator to forward all edge traffic to the NLB.&lt;/li&gt;
&lt;li&gt;  An internal service which authorizes Caddy to provision certificates for only the domains that we explicitly allow.&lt;/li&gt;
&lt;li&gt;  Additional internal DNS records to map custom domain names to their respective deployments.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This design was simple, but lacked one important component: a &lt;a href="https://aws.amazon.com/waf/"&gt;Web Application Firewall&lt;/a&gt; (WAF). We use AWS's WAF to protect our customers' deployments against DDoS and bot attacks.&lt;/p&gt;

&lt;p&gt;Since WAF can only inspect plaintext traffic and only works with ALBs, we had to insert a new ALB between Caddy and our customer deployments to get this protection. The alternative was running a WAF from a different vendor, which is possible but would balloon the scope of this project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ww5w3TGl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jay9nskibkyqw8rp8j7p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ww5w3TGl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jay9nskibkyqw8rp8j7p.png" alt="Unlimited Custom Domains Diagram" width="800" height="570"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A Wrinkle With The WAF
&lt;/h2&gt;

&lt;p&gt;A WAF can also get in the way sometimes. Integrations requiring frequent API access occasionally trigger DDoS rules, which means legitimate traffic is blocked. Customers may wish to add certain static IP addresses to an allowlist, guaranteeing unfettered access to their authentication servers.&lt;/p&gt;

&lt;p&gt;To implement the allowlist, we need to know the source IP address of the traffic as it enters the Global Accelerator.&lt;/p&gt;

&lt;p&gt;Luckily for us, Global Accelerator has an option to preserve the client IP address, so Caddy can pass it through in an &lt;code&gt;X-Fowarded-For&lt;/code&gt; header where the WAF can compare it against our allow lists.&lt;/p&gt;

&lt;p&gt;Unluckily for us, this option is only &lt;a href="https://docs.aws.amazon.com/global-accelerator/latest/dg/preserve-client-ip-address.html"&gt;available&lt;/a&gt; when Global Accelerator is forwarding traffic to either an ALB or directly to EC2 instances. Since using an ALB here would re-introduce the limitations that we're trying to workaround, we were forced to ditch Fargate and use bare EC2 instances as our ECS capacity provider.&lt;/p&gt;

&lt;p&gt;Running ECS workloads on EC2 is not difficult, but does require us to build out the automation to deploy, scale and keep the instances up to date. The Global Accelerator's endpoint group must also remain in sync with these instances.&lt;/p&gt;

&lt;p&gt;These instances need to do only one thing: run Caddy containers. In order to minimize the attack surface, we did not want them running any services other than Docker. They do not need to run SSHD or most other services which are included in standard Linux distributions, so we searched for the most minimal distribution that would satisfy our basic requirements.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://aws.amazon.com/bottlerocket"&gt;Bottlerocket&lt;/a&gt; is one such distribution. It is maintained by AWS, includes only the necessities to run Docker containers and it easily integrates with ECS. After building out our new ECS cluster with Bottlerocket as a base image, we found that our Caddy containers were failing to start with only a cryptic error message pointing to a failed EFS mount.&lt;/p&gt;

&lt;p&gt;We verified that all of the IAM roles, security groups and file system policies were correct, but finally came across this &lt;a href="https://github.com/bottlerocket-os/bottlerocket/issues/1080"&gt;issue&lt;/a&gt;. Bottlerocket does not support authenticated EFS volumes, and probably never will.  &lt;/p&gt;

&lt;p&gt;The next best distribution turned out to be Amazon's ECS-optimized AMI. It wasn't as minimal as Bottlerocket, but with some tweaks we were able to lock it down and swap it into our ECS cluster. After this change, everything was working. From dynamic certificate provisioning to load balancing to deployment routing.&lt;/p&gt;

&lt;p&gt;At last, we had fully integrated Caddy end-to-end into our infrastructure. Our existing monitoring and alerting systems were easily attached to the new resources and we found no issues during our final testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Means For FusionAuth Cloud Customers
&lt;/h2&gt;

&lt;p&gt;With this architecture change we can now support unlimited custom domains in FusionAuth Cloud. Whatever your use case -- we can handle it. All plans include a private instance (no shared public cloud) fully managed by FusionAuth, with options for backup, custom availability zones, uptime SLAs, and more to meet your infrastructure requirements.&lt;/p&gt;

&lt;p&gt;You can start a &lt;a href="https://dev.to/pricing?step%3Dhosting"&gt;free trial of FusionAuth Cloud&lt;/a&gt; now or for more complex projects or infrastructure questions, reach out to our &lt;a href="https://dev.to/contact"&gt;identity experts&lt;/a&gt; for help.&lt;/p&gt;

</description>
      <category>fusionauthcloud</category>
      <category>aws</category>
      <category>domains</category>
      <category>caddy</category>
    </item>
    <item>
      <title>Introducing Unlimited Custom Domains for FusionAuth Cloud</title>
      <dc:creator>FusionAuth</dc:creator>
      <pubDate>Tue, 25 Jul 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/fusionauth/introducing-unlimited-custom-domains-for-fusionauth-cloud-ebh</link>
      <guid>https://dev.to/fusionauth/introducing-unlimited-custom-domains-for-fusionauth-cloud-ebh</guid>
      <description>&lt;p&gt;Today, we’re announcing Unlimited Custom Domains for &lt;a href="https://fusionauth.io/platform/fusionauth-cloud"&gt;FusionAuth Cloud&lt;/a&gt;. Custom domains allow you to associate another domain with your FusionAuth Cloud deployment without having to fuss with certificate issuance and renewal – it just works.&lt;/p&gt;

&lt;p&gt;Let’s take a look at the changes now and stay tuned for a future blog on how we engineered this feature (hint - it involves &lt;a href="https://caddyserver.com/"&gt;Caddy&lt;/a&gt;, an open-source project we are proud to support).&lt;/p&gt;

&lt;h2&gt;
  
  
  What are Custom Domains?
&lt;/h2&gt;

&lt;p&gt;Custom domains let you brand your login experience and have your users see a domain they recognize – yours. Instead of seeing &lt;code&gt;piedpiper.fusionauth.io&lt;/code&gt; in your login page’s URL, adding a custom domain allows you to set it as &lt;code&gt;auth.piedpiper.com.&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  But Wait, Custom Domains Aren’t New
&lt;/h2&gt;

&lt;p&gt;That’s true! Custom domains have been available for FusionAuth Cloud since 2021, but we supported a maximum of 4 custom domains, even on our High Availability hosting plan. Adding more than that required using a &lt;a href="https://fusionauth.io/docs/v1/tech/admin-guide/proxy-setup"&gt;proxy&lt;/a&gt; layer like CloudFlare, Apache, or CloudFront and extra work for FusionAuth Cloud customers to manage those domains and certificates.&lt;/p&gt;

&lt;p&gt;That got us thinking… why limit it to 4? And how could we streamline the process for customers?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So as of today, these changes are now in effect for FusionAuth Cloud:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;High Availability Hosting now includes Unlimited Custom Domains.&lt;/li&gt;
&lt;li&gt;A streamlined user interface for managing custom domains within the FusionAuth admin portal.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---J5maFUk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/assets/img/blogs/unlimited-custom-domains/fusionauth-cloud-custom-domains.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---J5maFUk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/assets/img/blogs/unlimited-custom-domains/fusionauth-cloud-custom-domains.png" alt="Introducing Unlimited Custom Domains." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Add a Custom Domain
&lt;/h2&gt;

&lt;p&gt;If you are on a supported deployment and want a custom domain name such as &lt;code&gt;auth.piediper.com&lt;/code&gt;, it’s now entirely self-service. Log in to your account portal, navigate to &lt;strong&gt;Deployments&lt;/strong&gt; and then select &lt;strong&gt;Custom URL(s)&lt;/strong&gt; under the &lt;strong&gt;Action&lt;/strong&gt; dropdown. Check out the custom domains &lt;a href="https://dev.to/docs/v1/tech/installation-guide/cloud#unlimited-custom-domains"&gt;documentation&lt;/a&gt; for details about how to add the domain name and update an existing domain record.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CYA4v_rl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/assets/img/blogs/unlimited-custom-domains/managing-domains-fusionauth-cloud.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CYA4v_rl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/assets/img/blogs/unlimited-custom-domains/managing-domains-fusionauth-cloud.png" alt="Managing a Custom Domain." width="800" height="799"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Other customer identity and access management platforms typically only offer one custom domain as standard. If you need more than that, some vendors even make you pay an extra fee per domain. With FusionAuth, it’s just another feature we are adding to support our &lt;a href="https://dev.to/blog/2023/03/15/winning-customer-auth-market"&gt;growing customer base&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;FusionAuth Cloud offers different hosting tier selections to give you a choice for your deployment needs. All plans include a private instance (no shared public cloud) fully managed by FusionAuth, with options for backup, custom availability zones, uptime SLAs, and more to meet your infrastructure requirements.&lt;/p&gt;

&lt;p&gt;You can start a &lt;a href="https://fusionauth.io/pricing?step=hosting"&gt;free trial of FusionAuth Cloud&lt;/a&gt; now or for more complex projects or infrastructure questions, reach out to our &lt;a href="https://fusionauth.io/contact"&gt;identity experts&lt;/a&gt; for help.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Contenda used FusionAuth instead of rolling their own auth stack and saved "a lot" of time</title>
      <dc:creator>FusionAuth</dc:creator>
      <pubDate>Mon, 17 Jul 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/fusionauth/contenda-used-fusionauth-instead-of-rolling-their-own-auth-stack-and-saved-a-lot-of-time-2emf</link>
      <guid>https://dev.to/fusionauth/contenda-used-fusionauth-instead-of-rolling-their-own-auth-stack-and-saved-a-lot-of-time-2emf</guid>
      <description>&lt;p&gt;Tamás Deme is a FusionAuth community member and engineering lead at Contenda. Grady Salzman is a FusionAuth community member and software engineer at Contenda. They chatted with us over email about how they and their team are using FusionAuth to meet their auth needs.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This interview has been lightly edited for clarity and length.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Dan:&lt;/strong&gt; Can you tell me a bit about Contenda? What is the company's mission?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tamás and Grady:&lt;/strong&gt; Contenda is a content creation tool designed to enable anyone on a team to take any video, such as a conference talk, interview, or demo, and turn it into effective written content. It features an easy-to-use upload, transformation, and customization system, a powerful API to automate content production pipelines, and is built specifically for developer advocates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dan:&lt;/strong&gt; What are some examples of features/functionality that are useful specifically for developer advocates?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tamás and Grady:&lt;/strong&gt; Our platform is capable of grabbing and re-formatting code-snippets from videos, and we made sure our editor uses and works well with Markdown, which is generally preferred by the dev advocate community.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dan:&lt;/strong&gt; What is the company's mission?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tamás and Grady:&lt;/strong&gt; To democratize and increase quality written content creation for users &amp;amp; organizations.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[Auth is] a gigantic headache to do on your own; it's easy to get suffocated in a sea of edge cases.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Dan:&lt;/strong&gt; Tell me more about democratization. Can't anyone write good content? (Thank you, Tim Berners-Lee!) What am I missing?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tamás and Grady:&lt;/strong&gt; We believe that creating technical content should be accessible to everyone, no matter their experience level. What's "good" is not necessarily clear cut, as at minimum it starts a discussion and provides an understanding of everyone's point of view, which can then facilitate learning and correcting any misconceptions.&lt;/p&gt;

&lt;p&gt;When we talk about quality we think about how accurately we can represent the original content we process, and make sure we don't make up things the original creator never intended to say.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dan:&lt;/strong&gt; Tell me about your work as engineers at Contenda.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Grady:&lt;/strong&gt; I am the front end engineer, and I am responsible for building out our web app. For this integration, I did anything that wasn't backend. This included implementing the FusionAuth themes and hooking FusionAuth up to our web app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tamás:&lt;/strong&gt; My job as the engineering lead is to drive the architectural, infrastructure and backend efforts at the company, and generally help the other engineers grow as the company grows.&lt;/p&gt;

&lt;p&gt;Specifically for this integration process, I've mostly done everything that wasn't the frontend - starting with analyzing and choosing an auth provider, to performing the required database and backend changes, and handling the migration and support now that we've launched.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dan:&lt;/strong&gt; How do you use FusionAuth? OAuth? User management? Social sign-on? Something else?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tamás and Grady:&lt;/strong&gt; We use FusionAuth for almost all of our user management needs, except maybe for our workspace management. This includes doing authentication for our web app and our API. FusionAuth handles standard email/password sign ups and social sign ups as well.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dan:&lt;/strong&gt; For your API, are you using the client credentials grant, or a JWT from the authorization code grant or something else?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tamás and Grady:&lt;/strong&gt; Right now we're using the &lt;a href="https://dev.to/docs/v1/tech/tutorials/application-authentication-tokens"&gt;Application Authentication Token&lt;/a&gt; feature/API to get JWTs, although we might change that up in the future.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We appreciate that FusionAuth doesn't have any "trap-like" pricing practices that could bite us when we happen to approach an arbitrary number of users.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Dan:&lt;/strong&gt; From a user management perspective, do you interact with the FusionAuth admin UI or the APIs plus a custom app?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tamás and Grady:&lt;/strong&gt; Yes, that's mostly correct. Our own tools for our own backend aren't as sophisticated just yet, but we'll get there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dan:&lt;/strong&gt; What problems did we solve for you?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tamás:&lt;/strong&gt; To sum up, all of auth. Unless you're a major player (and sometimes even then), rolling your own auth stack is probably a bad idea, so we've always been planning on looking for a reliable 3rd party provider to handle all this for us. It's a gigantic headache to do on your own; it's easy to get suffocated in a sea of edge cases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dan:&lt;/strong&gt; How were you solving them before FusionAuth?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tamás and Grady:&lt;/strong&gt; In the past we've used a very bare bones, API key only sign-up system we put together in under a week.&lt;/p&gt;

&lt;p&gt;While it served us getting our first 1000 users, we definitely needed something more robust, secure and user-friendly to get to the next magnitude of users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dan:&lt;/strong&gt; What did you use for the first system? Was it framework based, a library, or something else?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tamás and Grady:&lt;/strong&gt; It was a completely custom implementation, just the very basics really.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We could've spent months working on a complex system, and any FusionAuth employee could still say "Look what they need to mimic a fraction of our power" after that.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Dan:&lt;/strong&gt; Why did you choose FusionAuth over the alternatives?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tamás and Grady:&lt;/strong&gt; After we eliminated all the options we had to rule out due to technical limitations, the two main reasons were cost and "friendliness".&lt;/p&gt;

&lt;p&gt;While the price itself is one thing, by "friendliness" I mean both support and the pricing strategies down the line. We appreciate that FusionAuth doesn't have any "trap-like" pricing practices that could bite us when we happen to approach an arbitrary number of users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dan:&lt;/strong&gt; What were some of the technical limitations you had that disqualified folks initially?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tamás and Grady:&lt;/strong&gt; It was mostly due to them not having react and/or python clients/SDKs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dan:&lt;/strong&gt; I love the term "friendliness". Are there any other software packages you use that feel like they win in that category (other than FusionAuth and Contenda, of course)?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tamás and Grady:&lt;/strong&gt; On our frontend, we use Netlify and Pendo, and I think we could put them in this bucket as well. Generally smaller companies tend to care more about their customers, so it's not always the best idea to go with the biggest player out there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dan:&lt;/strong&gt; How much time and money would you say FusionAuth has saved you?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tamás:&lt;/strong&gt; While I don't think I can come up with an exact number for either of those, I can confidently say: a lot. We could've spent months working on a complex system, and any FusionAuth employee could still say "Look what they need to mimic a fraction of our power" after that.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[After building our own auth system in under a week] we definitely need something more robust, secure and user-friendly to get to the next magnitude of users.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Dan:&lt;/strong&gt; How do you run FusionAuth (kubernetes, standalone server, behind a proxy, etc)?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tamás and Grady:&lt;/strong&gt; We don't actually; you do!&lt;/p&gt;

&lt;p&gt;This was also an important point for us: engineering-hours are always the limiting factor, so if we can find a provider that also handles the infrastructure for us, that's fewer hours we waste on managing something we don't have to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dan:&lt;/strong&gt; Any general feedback/areas to improve?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tamás:&lt;/strong&gt; I'd love it if more things were "easy" on the "easy &amp;lt;-&amp;gt; possible" scale. FusionAuth is extremely customizable, which is great, and makes a lot of things possible.&lt;/p&gt;

&lt;p&gt;But it'd be nice if the configuration interface would self-document itself more, and make a lot of the typical use-cases easy and simpler to do.&lt;/p&gt;

&lt;p&gt;Also, as a fan of strong typing: adding type hints to the python client library would be tremendous.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dan:&lt;/strong&gt; Thanks for your feedback!&lt;/p&gt;




&lt;p&gt;We love sharing community stories. You can check out &lt;a href="https://contenda.co/"&gt;Contenda's website&lt;/a&gt; if you'd like to learn more about them.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Adding single sign-on to a Next.js app using OIDC</title>
      <dc:creator>FusionAuth</dc:creator>
      <pubDate>Wed, 26 Apr 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/fusionauth/adding-single-sign-on-to-a-nextjs-app-using-oidc-4g1b</link>
      <guid>https://dev.to/fusionauth/adding-single-sign-on-to-a-nextjs-app-using-oidc-4g1b</guid>
      <description>&lt;p&gt;Single sign-on (SSO) is a session and user authentication technique that permits a user to use one set of login credentials to authenticate with multiple apps. SSO works by establishing trust between a service provider, usually your application, and an identity provider, like FusionAuth.&lt;/p&gt;

&lt;p&gt;The trust is established through an out-of-band exchange of cryptographic credentials, such as a client secret or public key infrastructure (PKI) certificate. Once trust has been established between the service provider and the identity provider, SSO authentication can occur when a user wants to authenticate with the service provider. This will typically involve the service provider sending a token to the identity provider containing details about the user seeking authentication. The identity provider can then check if the user is already authenticated and ask them to authenticate if they are not. Once this is done, the identity provider can send a token back to the service provider, signifying that the user has been granted access.&lt;/p&gt;

&lt;p&gt;SSO helps reduce password fatigue by requiring users to only remember one password and username for all the applications managed through the SSO feature. This also reduces the number of support tickets created for your IT team when a user inevitably forgets their password. In addition, SSO minimizes the number of times you have to key-in security credentials, limiting exposure to security issues like keystroke probing and exposure. Security is also enhanced by SSO because you can implement additional functionality such as MFA or anomalous behavior detection at the identity provider without adding any complexity to your application.&lt;/p&gt;

&lt;p&gt;In this tutorial, you’ll learn how to design and implement SSO using &lt;a href="https://nextjs.org/"&gt;Next.js&lt;/a&gt;, a popular React-based framework for JavaScript and FusionAuth as the OIDC provider. Any other OIDC compatible authentication server should work as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing SSO in a Next.js web app
&lt;/h2&gt;

&lt;p&gt;As previously stated, in this tutorial, you’ll be shown how to implement SSO in a Next.js web app. The Next.js demo application is integrated with FusionAuth, an authentication and authorization platform, and &lt;a href="https://next-auth.js.org"&gt;NextAuth.js&lt;/a&gt;, a complete open-source authentication solution, in this article.&lt;/p&gt;

&lt;p&gt;Before you begin, you’ll need the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Linux machine. The step-by-step instructions in this article are based on a &lt;a href="https://www.centos.org"&gt;CentOS Linux machine&lt;/a&gt;. If you want to work on a different OS, check out this &lt;a href="https://dev.to/docs/v1/tech/5-minute-setup-guide"&gt;setup guide&lt;/a&gt; for more information.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.docker.com/engine/"&gt;Docker Engine&lt;/a&gt; and &lt;a href="https://docs.docker.com/compose/"&gt;Docker Compose&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.npmjs.com/downloading-and-installing-node-js-and-npm"&gt;Node.js&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Experience with &lt;a href="https://nextjs.org/"&gt;Next.js&lt;/a&gt; framework and application development.&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://git-scm.com/downloads"&gt;Git client tool&lt;/a&gt; &lt;em&gt;(optional)&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Installing FusionAuth
&lt;/h2&gt;

&lt;p&gt;If you already have a FusionAuth Cloud instance, you can use that, but for the sake of simplicity, this tutorial will assume you are using a locally hosted instance. There are detailed setup guides in the &lt;a href="https://dev.to/docs/v1/tech/installation-guide/docker/"&gt;documentation&lt;/a&gt;, but the short version is that once you have Docker and Docker Compose set up and installed correctly, you can run the following command in a new directory to download and execute the necessary files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -o docker-compose.yml https://raw.githubusercontent.com/FusionAuth/fusionauth-containers/master/docker/fusionauth/docker-compose.yml curl -o .env https://raw.githubusercontent.com/FusionAuth/fusionauth-containers/master/docker/fusionauth/.env docker compose up 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Starting FusionAuth
&lt;/h3&gt;

&lt;p&gt;Once the FusionAuth service is started, open a browser and access &lt;a href="http://localhost:9011/"&gt;http://localhost:9011/&lt;/a&gt;, where you’ll be taken to the &lt;strong&gt;“FusionAuth Setup Wizard”&lt;/strong&gt; , as seen in the image below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tt1PI8FM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/assets/img/blogs/includes/fusionauth/setup-wizard.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tt1PI8FM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/assets/img/blogs/includes/fusionauth/setup-wizard.png" alt="FusionAuth setup wizard." width="800" height="758"&gt;&lt;/a&gt; &lt;br&gt;
&lt;em&gt;FusionAuth setup wizard.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Fill in the admin user account details, read and accept the License Agreement. When you are ready, click &lt;strong&gt;“Submit”&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Learn more about the &lt;a href="https://fusionauth.io/docs/v1/tech/tutorials/setup-wizard"&gt;Setup Wizard here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After submitting, you’ll be taken to a login screen where you need to fill in the credentials you specified during the setup wizard and sign in to the FusionAuth administrative user interface. Later, you’ll use the same admin account for testing the SSO of the application.&lt;/p&gt;
&lt;h3&gt;
  
  
  Configure FusionAuth
&lt;/h3&gt;

&lt;p&gt;Now you need to configure FusionAuth by creating an application and registering the user.&lt;/p&gt;

&lt;p&gt;This setup allows users in FusionAuth to sign in to the Next.js application automatically once they are authenticated by FusionAuth.&lt;/p&gt;
&lt;h3&gt;
  
  
  Set up the application
&lt;/h3&gt;

&lt;p&gt;To set up the application, navigate to the &lt;a href="http://localhost:9011/admin"&gt;FusionAuth admin UI&lt;/a&gt; and select “Applications” on the left-hand navigation bar:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---xCOJ7JO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/assets/img/blogs/includes/fusionauth/set-up-the-application.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---xCOJ7JO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/assets/img/blogs/includes/fusionauth/set-up-the-application.png" alt="Set up the application." width="800" height="408"&gt;&lt;/a&gt; &lt;br&gt;
&lt;em&gt;Set up the application.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Then click on the “+” button on the top right of the “Applications” page and fill in the “Name” field with a name of your choosing (here, it’s &lt;strong&gt;“your_application”&lt;/strong&gt; ):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PB9hySqY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/assets/img/blogs/includes/fusionauth/name-the-application.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PB9hySqY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/assets/img/blogs/includes/fusionauth/name-the-application.png" alt="Name your application." width="800" height="610"&gt;&lt;/a&gt; &lt;br&gt;
&lt;em&gt;Name your application.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can leave all the other fields empty because FusionAuth will choose a default value for those fields. Go ahead and save the application in order for the Client Id details to be generated.&lt;/p&gt;

&lt;p&gt;Access the “Application” page again and click on the “Edit Applications” icon (a little edit/notepad icon):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hsL3UYHT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/assets/img/blogs/includes/fusionauth/edit-application.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hsL3UYHT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/assets/img/blogs/includes/fusionauth/edit-application.png" alt="The list of applications. The edit icon is the blue pencil/notepad." width="800" height="408"&gt;&lt;/a&gt; &lt;br&gt;
&lt;em&gt;The list of applications. The edit icon is the blue pencil/notepad.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;On the “Edit Application” page, click on the “OAuth” tab at the top. You’ll need to get some information from this page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--syubmWJP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/assets/img/blogs/nextjs-single-sign-on/fusionauth-callback.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--syubmWJP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/assets/img/blogs/nextjs-single-sign-on/fusionauth-callback.png" alt="The OAuth details tab." width="800" height="814"&gt;&lt;/a&gt; &lt;br&gt;
&lt;em&gt;The OAuth details tab.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Record the generated “Client Id” and the “Client Secret” in a text file or to the clipboard. You’ll use these below.&lt;/li&gt;
&lt;li&gt;Add the value &lt;code&gt;http://localhost:3000/api/auth/callback/fusionauth&lt;/code&gt; to the “Authorized redirect URLs” field. This will be used by FusionAuth to redirect the user to your application page once the user is successfully authenticated.&lt;/li&gt;
&lt;li&gt;Scroll down and check the “Require registration” checkbox. This ensures that users who haven’t been registered for this application in FusionAuth aren’t able to access it when using the hosted login pages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After filling in the details, click the “Save” icon.&lt;/p&gt;

&lt;p&gt;You aren’t limited to one application, by the way. If you have multiple applications, or even other applications like Zendesk or forum software, set them up here to enable SSO.&lt;/p&gt;
&lt;h3&gt;
  
  
  Register the user
&lt;/h3&gt;

&lt;p&gt;Next, register the user for the application. Navigate to the “Users” tab and find your user. Click on the black “Manage User” button under the “Action” heading in the list. You’ll end up at the details page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eWnYFsz6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/assets/img/blogs/includes/fusionauth/register-user.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eWnYFsz6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/assets/img/blogs/includes/fusionauth/register-user.png" alt="The user details screen, where you can register them." width="800" height="675"&gt;&lt;/a&gt; &lt;br&gt;
&lt;em&gt;The user details screen, where you can register them.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Click “Add registration” to register the user in &lt;code&gt;your_application&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZYLxJP4E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/assets/img/blogs/includes/fusionauth/add-registration.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZYLxJP4E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/assets/img/blogs/includes/fusionauth/add-registration.png" alt="Adding the user registration." width="800" height="635"&gt;&lt;/a&gt; &lt;br&gt;
&lt;em&gt;Adding the user registration.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If users of this application have unique configuration details, such as a username, timezone, or languages, which are different from the user’s defaults, you could configure them here.&lt;/p&gt;

&lt;p&gt;However, for this tutorial, you can click the blue “Save” button and accept the default values.&lt;/p&gt;
&lt;h3&gt;
  
  
  Kickstart
&lt;/h3&gt;

&lt;p&gt;Instead of manually setting up FusionAuth using the admin UI as you did above, you can use Kickstart. This tool allows you to get going quickly if you have a fresh installation of FusionAuth. Learn more about how to use &lt;a href="https://dev.to/docs/v1/tech/installation-guide/kickstart"&gt;Kickstart&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here’s an example &lt;a href="https://github.com/FusionAuth/fusionauth-example-nextjs-single-sign-on/blob/main/kickstart/kickstart.json"&gt;Kickstart file&lt;/a&gt; which sets up FusionAuth for this tutorial.&lt;/p&gt;
&lt;h2&gt;
  
  
  Create the Next.js application
&lt;/h2&gt;

&lt;p&gt;You have two options here. You can either clone a working example, or build the app from scratch.&lt;/p&gt;
&lt;h3&gt;
  
  
  Clone the demo repository
&lt;/h3&gt;

&lt;p&gt;If you want to run an already working application, you can clone the demo project from this &lt;a href="https://github.com/FusionAuth/fusionauth-example-nextjs-single-sign-on"&gt;GitHub repository&lt;/a&gt; using the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone git@github.com:FusionAuth/fusionauth-example-nextjs-single-sign-on.git 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since you’ve cloned a working rep, you don’t need to follow the next section. If you’d like to understand more about what was done in the demo application, feel free to read them.&lt;/p&gt;

&lt;p&gt;Either way, continue configuring the Environment variables to proceed with this tutorial.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create your own Next.js application
&lt;/h2&gt;

&lt;p&gt;If you want to create your own application instead of using our demo project, you can create a new Next.js application by running the command below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-next-app name-of-your-application 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;If it is your first time creating a Next.js application, you’ll be prompted to install the &lt;code&gt;create-next-app&lt;/code&gt; package. Just type &lt;code&gt;y&lt;/code&gt; to accept it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;code&gt;create-next-app&lt;/code&gt; wizard will ask you a few questions on how to set up your application. Answer them like shown.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✔ Would you like to use TypeScript with this project? … No ✔ Would you like to use ESLint with this project? … Yes ✔ Would you like to use `src/` directory with this project? … Yes ? Would you like to use experimental `app/` directory with this project? … No ✔ What import alias would you like configured? … @/* 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enter the directory for the application you created and start up the application by running these commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd name-of-your-application npm run dev 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Browse to &lt;a href="http://localhost:3000"&gt;localhost:3000&lt;/a&gt;. If the installation went successful, you should see the default welcome page from Next.js.&lt;/p&gt;

&lt;p&gt;Now that you have the application running, let’s implement the authentication process by using &lt;a href="https://next-auth.js.org"&gt;NextAuth.js&lt;/a&gt;, a complete open-source solution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing NextAuth.js
&lt;/h3&gt;

&lt;p&gt;We recommend you look at the &lt;a href="https://next-auth.js.org/getting-started/example"&gt;NextAuth.js Getting Start guide&lt;/a&gt; for the most up-to-date instructions.&lt;/p&gt;

&lt;p&gt;First, install NextAuth.js.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install next-auth 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, you need to create a file named exactly like &lt;code&gt;[...nextauth].js&lt;/code&gt; in &lt;code&gt;src/pages/api/auth&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First, make the directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir src/pages/api/auth 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create a file named &lt;code&gt;[...nextauth].js&lt;/code&gt; in that directory.&lt;/p&gt;

&lt;p&gt;Next, you’ll configure the &lt;a href="https://next-auth.js.org/providers/fusionauth"&gt;built-in support for FusionAuth&lt;/a&gt;. Doing so ensures every request to the &lt;code&gt;/api/auth/*&lt;/code&gt; path is handled by NextAuth.js.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import NextAuth from "next-auth" import FusionAuthProvider from "next-auth/providers/fusionauth" export const authOptions = { providers: [FusionAuthProvider({ issuer: process.env.FUSIONAUTH_ISSUER, clientId: process.env.FUSIONAUTH_CLIENT_ID, clientSecret: process.env.FUSIONAUTH_CLIENT_SECRET, wellKnown: `${process.env.FUSIONAUTH_URL}/.well-known/openid-configuration/${process.env.FUSIONAUTH_TENANT_ID}`, tenantId: process.env.FUSIONAUTH_TENANT_ID, // Only required if you're using multi-tenancy }),], } export default NextAuth(authOptions) 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Exposing session state
&lt;/h3&gt;

&lt;p&gt;To allow components to check whether the current user is logged in, change &lt;code&gt;src/pages/_app.js&lt;/code&gt; to have your application rendered inside a &lt;code&gt;&amp;lt;SessionProvider&amp;gt;&lt;/code&gt; context, like shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import '@/styles/globals.css' import { SessionProvider } from "next-auth/react" export default function App({ Component, pageProps: {session, ...pageProps}, }) { return ( &amp;lt;SessionProvider session={session}&amp;gt; &amp;lt;Component {...pageProps} /&amp;gt; &amp;lt;/SessionProvider&amp;gt; ); } 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will make the &lt;a href="https://next-auth.js.org/getting-started/client#usesession"&gt;&lt;code&gt;useSession()&lt;/code&gt;&lt;/a&gt; React Hook accessible to your entire application.&lt;/p&gt;

&lt;p&gt;Now, create a component that will either render a “Log in” or “Log out” button, depending on the session state, in a &lt;code&gt;src/components/login-button.jsx&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useSession, signIn, signOut } from "next-auth/react" export default function Component() { const { data: session } = useSession() if (session) { return ( &amp;lt;&amp;gt; Status: Logged in as {session.user.email} &amp;lt;br /&amp;gt; &amp;lt;button onClick={() =&amp;gt; signOut()}&amp;gt;Log out&amp;lt;/button&amp;gt; &amp;lt;/&amp;gt; ) } return ( &amp;lt;&amp;gt; Status: Not logged in &amp;lt;br /&amp;gt; &amp;lt;button onClick={() =&amp;gt; signIn()}&amp;gt;Log in&amp;lt;/button&amp;gt; &amp;lt;/&amp;gt; ) } 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, you change your home component located at &lt;code&gt;src/pages/index.js&lt;/code&gt; to include the &lt;code&gt;&amp;lt;LoginButton /&amp;gt;&lt;/code&gt; component inside &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Head from 'next/head' import LoginButton from '@/components/login-button' export default function Home() { return ( &amp;lt;&amp;gt; &amp;lt;Head&amp;gt; &amp;lt;title&amp;gt;Next.js + FusionAuth&amp;lt;/title&amp;gt; &amp;lt;meta name="description" content="Sample app to demonstrate implementing authentication in a Next.js application with FusionAuth" /&amp;gt; &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1" /&amp;gt; &amp;lt;link rel="icon" href="/favicon.ico" /&amp;gt; &amp;lt;/Head&amp;gt; &amp;lt;main&amp;gt; &amp;lt;LoginButton /&amp;gt; &amp;lt;/main&amp;gt; &amp;lt;/&amp;gt; ) } 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Environment variables
&lt;/h2&gt;

&lt;p&gt;If you cloned the demo repository, you can copy &lt;code&gt;.env.local.dist&lt;/code&gt; to &lt;code&gt;.env.local&lt;/code&gt; and change the values there. If not, create a &lt;code&gt;.env.local&lt;/code&gt; file and fill in the details from your FusionAuth application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# example: my-website.com FUSIONAUTH_ISSUER=http://localhost:9011 FUSIONAUTH_CLIENT_ID=e9fdb985-9173-4e01-9d73-ac2d60d1dc8e FUSIONAUTH_CLIENT_SECRET=super-secret-secret-that-should-be-regenerated-for-production # Leave blank if you only have the default tenant FUSIONAUTH_TENANT_ID= # example: http://localhost:9011 FUSIONAUTH_URL=http://localhost:9011 # you can run `openssl rand -base64 32` NEXTAUTH_SECRET=random_value_please_change 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Start the HTTP server by running the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run dev 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Browse to &lt;a href="http://localhost:3000"&gt;localhost:3000&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VdekgrUp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/assets/img/blogs/nextjs-single-sign-on/before-login.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VdekgrUp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/assets/img/blogs/nextjs-single-sign-on/before-login.png" alt="The initial nextjs screen." width="800" height="182"&gt;&lt;/a&gt; &lt;br&gt;
&lt;em&gt;The initial nextjs screen.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Click the “Log in” button to be taken to a page with a “Sign in with FusionAuth” button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XwqbRcE0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/assets/img/blogs/nextjs-single-sign-on/ask-for-login.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XwqbRcE0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/assets/img/blogs/nextjs-single-sign-on/ask-for-login.png" alt="The sign-in button screen." width="800" height="814"&gt;&lt;/a&gt; &lt;br&gt;
&lt;em&gt;The sign-in button screen.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After clicking it, you should be redirected to your FusionAuth login screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OlO12KNt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/assets/img/blogs/nextjs-single-sign-on/login-screen.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OlO12KNt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/assets/img/blogs/nextjs-single-sign-on/login-screen.png" alt="The FusionAuth sign-in screen." width="800" height="389"&gt;&lt;/a&gt; &lt;br&gt;
&lt;em&gt;The FusionAuth sign-in screen.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Enter the correct credentials created when you set up FusionAuth and submit the form. You’ll arrive back at your Next.js application home screen, with your email address displayed and a “Log out” button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--k5H201Uv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/assets/img/blogs/nextjs-single-sign-on/after-login.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k5H201Uv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fusionauth.io/assets/img/blogs/nextjs-single-sign-on/after-login.png" alt="The nextjs application after logging in." width="800" height="191"&gt;&lt;/a&gt; &lt;br&gt;
&lt;em&gt;The nextjs application after logging in.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;What’s next?&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Make FusionAuth &lt;a href="https://dev.to/docs/v1/tech/themes/"&gt;look like your nextjs application using themes&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/learn/expert-advice/oauth/modern-guide-to-oauth/"&gt;Learn more about OAuth&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Build out a real nextjs application with a protected page.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>sso</category>
      <category>nextjs</category>
      <category>oidc</category>
    </item>
    <item>
      <title>Save on your AWS bill with this one simple trick</title>
      <dc:creator>FusionAuth</dc:creator>
      <pubDate>Mon, 03 Apr 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/fusionauth/save-on-your-aws-bill-with-this-one-simple-trick-2b83</link>
      <guid>https://dev.to/fusionauth/save-on-your-aws-bill-with-this-one-simple-trick-2b83</guid>
      <description>&lt;p&gt;With only a few clicks of the mouse, I saved 16% on my company’s AWS bill. Pretty sweet, eh?&lt;/p&gt;

&lt;p&gt;This article will show you why that matters, and how I did it.&lt;/p&gt;

&lt;h2&gt;
  
  
  FusionAuth Cloud lets you outsource operating your authentication service
&lt;/h2&gt;

&lt;p&gt;But first, let me set the scene. FusionAuth is &lt;a href="https://dev.to/download"&gt;downloadable software&lt;/a&gt; and running it is as simple as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -o docker-compose.yml https://raw.githubusercontent.com/FusionAuth/fusionauth-containers/master/docker/fusionauth/docker-compose.yml curl -o .env https://raw.githubusercontent.com/FusionAuth/fusionauth-containers/master/docker/fusionauth/.env docker-compose up 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have Docker installed, that’s all you have to do to get a FusionAuth instance up and running.&lt;/p&gt;

&lt;p&gt;After that, you need to integrate it with your application, typically using a standard OIDC library such as &lt;a href="https://www.passportjs.org/"&gt;Passport&lt;/a&gt; or &lt;a href="https://docs.spring.io/spring-security/reference/servlet/oauth2/client/index.html"&gt;Spring security&lt;/a&gt;. You need to &lt;a href="https://dev.to/docs/v1/tech/themes/"&gt;theme it&lt;/a&gt; to make it look like your application.&lt;/p&gt;

&lt;p&gt;But that’s it.&lt;/p&gt;

&lt;p&gt;With these steps, you get a full featured auth server, available on your laptop, for you to build against.&lt;/p&gt;

&lt;h3&gt;
  
  
  What about production?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;docker-compose up&lt;/code&gt; is great for development.&lt;/p&gt;

&lt;p&gt;But auth is the front door to your application, and should be highly available in production. Some of the considerations when running a FusionAuth production deployment include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;securing the application and servers&lt;/li&gt;
&lt;li&gt;backups and restores&lt;/li&gt;
&lt;li&gt;upgrades and rollbacks&lt;/li&gt;
&lt;li&gt;responding to DDOS attacks&lt;/li&gt;
&lt;li&gt;monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;FusionAuth Cloud, where the FusionAuth team operates FusionAuth, lets customers let us run FusionAuth for their authentication needs. It takes these tasks off your plate and puts them on that of the FusionAuth team.&lt;/p&gt;

&lt;p&gt;Now, there are many customers with the team, compliance needs, and desire to run FusionAuth themselves; we’re happy to support them in doing so with &lt;a href="https://dev.to/docs/v1/tech/installation-guide/cluster"&gt;documentation&lt;/a&gt; and customer support.&lt;/p&gt;

&lt;p&gt;But many users want to offload operational burdens and security concerns. In this aspect, FusionAuth Cloud is similar to a typical software as a service (SaaS) provider.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s so special about auth?
&lt;/h2&gt;

&lt;p&gt;But.&lt;/p&gt;

&lt;p&gt;An authentication service is not like any old SaaS application. Depending on your integration, it is embedded in your application. This is why Okta consistently has &lt;a href="https://investor.okta.com/static-files/8a461359-83f8-4332-9f41-eb7ee8c65c3b"&gt;negative churn&lt;/a&gt; on the order of 20%. Once you’re committed to an auth provider, it’s a biggish project to shift to another one.&lt;/p&gt;

&lt;p&gt;Worse, when your auth system breaks, your users don’t have access to your application. That’s bad.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--febGvPMD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://fusionauth.io/assets/img/blogs/aws-savings-plans/bad-time.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--febGvPMD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://fusionauth.io/assets/img/blogs/aws-savings-plans/bad-time.jpg" alt="It can be unpleasant when your users cannot log in." width="500" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because of these two attributes, with an auth provider you have requirements above and beyond those of a typical SaaS tool. FusionAuth Cloud offers the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It explicitly lets developers control the upgrade process; no required upgrades. You and your engineering team pick the version of software your application integrates with. You also choose how and when to upgrade. You can thoroughly test your integration when a new version comes out, rather than testing in prod or having new features foisted on you.&lt;/li&gt;
&lt;li&gt;Each customer is running on physically isolated single-tenant systems. Each FusionAuth Cloud deployment runs on separate virtual hardware, using Amazon’s best of breed managed services where appropriate.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Isolation in multi-tenant SaaS
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bgmg04-a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://fusionauth.io/assets/img/blogs/aws-savings-plans/isolation.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bgmg04-a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://fusionauth.io/assets/img/blogs/aws-savings-plans/isolation.jpg" alt="True isolation." width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s talk about isolation. When you offer a multi-tenant solution, with different customers using your application, there are multiple approaches to isolating their data and available functionality.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Logical isolation&lt;/strong&gt; is implemented using a &lt;code&gt;tenant_id&lt;/code&gt; field on tables (or using proprietary database functionality such as row level security). When a request comes in, the tenant is identified and only that tenant’s data is examined by the application. This is the cheapest and easiest multi-tenant solution to run. You have one set of servers and one primary datastore in production. However, if there are any flaws in the code, everyone’s data may be accessible. You can scale this system, but you can’t scale any individual customer’s application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Container level isolation&lt;/strong&gt; relies on containers and other software constructs such as Kubernetes namespaces. With this option, you have one set of servers underlying the containers in a cluster, though you can also outsource running it to a public cloud provider. Each customer gets their own set of containers running the code, as well as a separate database schema or server. This is more expensive, but provides a higher level of isolation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server isolation&lt;/strong&gt; is when you stand up separate virtual or physical machines. The application runs on each system. You can configure network layer protections such as firewalls, which increases the level of isolation. There’s also a lower chance of a noisy neighbor causing customers issues; the servers are separate. However, the operational cost is higher too.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;FusionAuth Cloud uses virtual machines and a shared-nothing architecture. Your data is isolated not within a database using foreign keys, but on physically separate machines.&lt;/p&gt;

&lt;h2&gt;
  
  
  FusionAuth Cloud and EC2
&lt;/h2&gt;

&lt;p&gt;This architecture leads to a lot of VMs, as you might imagine. As FusionAuth Cloud grows, the FusionAuth team is responsible for more and more virtual machines.&lt;/p&gt;

&lt;p&gt;Which brings us back to the beginning. During a &lt;a href="https://dev.to/blog/2022/09/27/hackfests-fusionauth"&gt;hackfest&lt;/a&gt;, I took a look at reserved instances because I was interested in the cost savings opportunities. Most of FusionAuth’s AWS spend is with EC2 and RDS.&lt;/p&gt;

&lt;p&gt;Many of our customers are on month to month plans, and the minimum AWS reserved instance length is one year (unless you are using the reserved instances marketplace, but I’m going to ignore that because it makes things complicated).&lt;/p&gt;

&lt;p&gt;Our customers also choose one of 15+ AWS regions in which to deploy their FusionAuth servers. This allows them to pick the region that makes sense for their performance, compliance and data sovereignty needs, while still outsourcing operations to the FusionAuth team. Reserved instances are tied to an AWS region, making it an awkward choice.&lt;/p&gt;

&lt;p&gt;While we could have projected a baseline of region usage and VM lifetime and bought reserved instances based on that, this felt like a bigger project than was suitable for a hackfest.&lt;/p&gt;

&lt;p&gt;However, after more research, I discovered &lt;a href="https://aws.amazon.com/savingsplans/compute-pricing/"&gt;AWS Compute Savings Plans&lt;/a&gt;. There is an EC2 version that “appl[ies] to EC2 instance usage regardless of instance family, size, AZ, Region, OS or tenancy”.&lt;/p&gt;

&lt;p&gt;Perfect!&lt;/p&gt;

&lt;h2&gt;
  
  
  How much can you save?
&lt;/h2&gt;

&lt;p&gt;FusionAuth Cloud adds new customers regularly, and churn happens, especially when someone tries our &lt;a href="https://fusionauth.io/pricing?step=plan&amp;amp;hosting=basic-cloud"&gt;Starter Plan free trial&lt;/a&gt; and determines that FusionAuth isn’t the right fit.&lt;/p&gt;

&lt;p&gt;I wanted to avoid automating the purchase of these plans, which felt like over-optimization. I began with a manual solution.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://us-east-1.console.aws.amazon.com/cost-management/home#/savings-plans/overview"&gt;Savings plan overview&lt;/a&gt; has a “Recommendations” tab. You can play with options and arrive at a savings amount. This helps you determine if you have enough spend to make buying a plan worth your time. To begin with, I chose “Compute Savings Plans”, a “1-year” term, and “No upfront” as the purchase commitment. You get a deeper discount for prepayment or a longer commitment.&lt;/p&gt;

&lt;p&gt;Here’s a table of the discounts available to us at time of writing. Check out the Savings plans section yourself to see your discount options.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;No Upfront&lt;/th&gt;
&lt;th&gt;All Upfront&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1 Year&lt;/td&gt;
&lt;td&gt;21%&lt;/td&gt;
&lt;td&gt;26%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3 Year&lt;/td&gt;
&lt;td&gt;45%&lt;/td&gt;
&lt;td&gt;49%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I could have saved more money, but going with a year term and no upfront cost gave the right mix of savings and flexibility. A 21% discount on EC2 usage we already know will be running 100% of the time?&lt;/p&gt;

&lt;p&gt;Yes please.&lt;/p&gt;

&lt;h3&gt;
  
  
  Buying the Compute Savings plan
&lt;/h3&gt;

&lt;p&gt;Here’s the screen where I purchased the plan.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gtPycXpC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://fusionauth.io/assets/img/blogs/aws-savings-plans/purchase-savings-plan.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gtPycXpC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://fusionauth.io/assets/img/blogs/aws-savings-plans/purchase-savings-plan.png" alt="The AWS cost explorer." width="880" height="895"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With Compute Savings plans, you are buying hours of instances, but paying in dollars per hour. It’s a bit weird, but makes sense when viewed in the bigger picture. After all, it’s an AWS bill, so it can’t be &lt;em&gt;too&lt;/em&gt; straightforward.&lt;/p&gt;

&lt;p&gt;Here’s an example to make it a bit clearer.&lt;/p&gt;

&lt;p&gt;Let’s say you have 20 X1E Extra Large EC2 instances. These bad boys each cost $0.6160 per hour. I don’t know what you’re doing with that much RAM, but whatever.&lt;/p&gt;

&lt;p&gt;With this, you have $12.32/hour of spend (20*0.616). To save money, if you know you will run these servers for a year or so, use a Compute Savings plan and buy down a portion of the $12.32. You could buy $5 of that hourly spend for $3.95, for instance.&lt;/p&gt;

&lt;p&gt;After you buy the plan, you will be billed for that $3.95 whether you run the instances or don’t. Your total hourly bill is now $11.27, a savings of $1.05 or 8.5% across your entire spend.&lt;/p&gt;

&lt;p&gt;The bottom line is that AWS is thrilled when you commit to spending money with them, and is therefore willing to pay you to do it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up a system
&lt;/h2&gt;

&lt;p&gt;Because of our growth, I wanted to avoid buying a savings plan as a one and done effort. I wanted a system that was lightweight, but would save us money as more customers came on board while preserving flexibility if we wanted to shift directions.&lt;/p&gt;

&lt;p&gt;Instead of buying the amount recommended by AWS, I bought 50% of it. In the future, we’ll do it again: purchase half of the recommended Compute Savings plan every few months.&lt;/p&gt;

&lt;p&gt;This will allow us to work towards having 100% of our usage covered by a savings plan. But we’ll never get there. Similar to &lt;a href="https://en.wikipedia.org/wiki/Zeno%27s_paradoxes"&gt;Achilles and the tortoise from Zeno’s paradox&lt;/a&gt; (image credit to wikipedia).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--w3E27CDQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://fusionauth.io/assets/img/blogs/aws-savings-plans/zeno-achilles-paradox.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--w3E27CDQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://fusionauth.io/assets/img/blogs/aws-savings-plans/zeno-achilles-paradox.png" alt="Achilles and the turtle, an example of Zeno's paradox. Image credit: wikipedia." width="440" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After determining that system would work, I documented it so I wouldn’t forget. This also lets others do this task if need be. Then I attached it to a recurring event in my calendar and promptly forgot about it. Every quarter or so, I get a reminder, and log into the AWS console and buy more discounted compute hours.&lt;/p&gt;

&lt;p&gt;This approach doesn’t maximize our savings, but it yields a useful amount (approximately 16% of our bill) and offers flexibility if our needs change. All at the cost of approximately 10 minutes every quarter.&lt;/p&gt;

&lt;p&gt;I’ve spent more time on this blog post than I have buying Compute Savings Plans over the past year. I’ll be honest, it’s fun to save thousands or tens of thousands of dollars with a single click and essentially zero downside.&lt;/p&gt;

&lt;p&gt;That’s the kind of clickops I can get behind.&lt;/p&gt;

&lt;h2&gt;
  
  
  Downsides of AWS Compute Savings plans
&lt;/h2&gt;

&lt;p&gt;What about that downside? Well, if FusionAuth ever needed to leave AWS, we’d have to plan ahead a year or so or eat the cost of the committed spend. However, migrating off any cloud provider, especially when your system is the front door for millions of your customers’ customers, isn’t a task you undertake on a whim. That downside is acceptable.&lt;/p&gt;

&lt;p&gt;We’re also not saving as much as we could. If we signed up for three years instead of one, we’d save more but lose flexibility. If we optimized, researched reserved instances (especially for RDS servers), and automated plan purchases, we could save even more. But we’ve made a conscious decision to focus on growth. Spending too much time optimizing cloud spend doesn’t align with that.&lt;/p&gt;

&lt;p&gt;10 minutes a quarter, on the other hand, is pretty easy to find.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summing up
&lt;/h2&gt;

&lt;p&gt;If you are running significant numbers of EC2 instances, there’s very little risk in investigating and implementing cost savings plans.&lt;/p&gt;

&lt;p&gt;Happy saving!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloud</category>
    </item>
  </channel>
</rss>
