Svelte Login Form Example: Best Practices

Rodney Lab - Jun 12 '23 - - Dev Community

📝 Signup Form Best Practices

In this post, we look at a Svelte login form example and see some security and user experience (UX) best practices. Clearly, good accessibility and overall UX help improve conversion rates. It is important, though, to stress the economic benefits of helping users implement good security before moving on.

In 2022 a credential stuffing attack on DraftKings, a US sports betting site, led to USD 300,000 being stolen from user accounts. Reports suggest there was no breach of DraftKings systems. Instead, the attacker is understood to have taken a list of user credentials leaked from other sites and tried them on DraftKings, in the hope users had recycled passwords. This is credential stuffing: trying to again access to a service using leaked or stolen passwords from another service.

This kind of attack is difficult for services to prevent. We focus on implementing some best practices to promote users improving their security in post, using a Svelte code examples.

Multifactor authentication

User best practices involve creating strong and unique passwords for each new account and setting up Multifactor Authentication where offered. Here FIDO U2F keys are the gold standard, with OTP apps like Authy and Google Authenticator offering a secure alternative. Passkeys, using the new WebAuthn standard might be a common, secure choice going forward. Passkeys will work with mobile devices, and you can enforce that the user authenticates using device biometrics (like a fingerprint check) for extra security.

🧑🏽 User Experience Recommendations

To help keep forms accessible, test them with tools like Lighthouse and Axe. Also try opening up the Issues tab in Chrome Dev tool as new Autofill and general form debugging features are rolling out in Chrome from May 2023. These will help with more general UX issues, as well as accessibility (making sure label elements have a for attribute matching an input, and so on).

For more general UX, remember to allow users to paste in passwords. Blocking pasting can be frustrating for password manager users. Finally, using autofill fields correctly can help users who store their passwords in-browser. Note, storing passwords in browser in not advised by some privacy advocates. See a longer checklist of sign-up best practices on web.dev.

🔐 OWASP recommendations

Ideally, your site will offer MFA and the Open Web Application Security Project (OWASP) has some recommendations, which also cover single factor authentication. These include:

  • enforcing a minimum and maximum password lengths
  • adding a password strength meter to encourage more complex passwords
  • blocking common and previously breached passwords

The minimum password length should be eight or more characters, and the maximum, long enough for users creating passphrases using diceware and other techniques. Enforcing a maximum length helps protect against some DoS attacks. We see a library below which can helps in adding a strength meter and spotting common passwords.

🧱 Svelte Login From: What we're Building

I put together a full demo implementing some of the best practices just mentioned. The demo includes an SQLite database, so you can spin it up, and test and tweak the techniques we discuss. We just look at the most important front end snippets here, and you can find the link to view the full repo further down.

🖋️ Signup Form

Let’s look at some code, staring with form elements on the new user signup form.

Username Input Field

<label for="email">Email</label>
<input
    id="email"
    aria-invalid={emailError}
    aria-describedby={emailError ? "email-error" : undefined}
    type="email"
    required
    name="email"
    autocomplete="username"
    value={email}
    placeholder="tillie@example.com"
/>
{#if errors?.email}
    <small id="email-error" class="error-text">{errors.email}</small>
{/if}
Enter fullscreen mode Exit fullscreen mode

Important points here for accessibility are:

  • the for attribute on the label element matches the input element id (both set to email)
  • the input uses aria-invalid and aria-describedby to provide feedback for screen reader users
  • the label is displayed here, if you want to hide it visually, keep it in the DOM but add a screen reader only class

Some browsers will use the type and required attributes to offer hints or even intercept submission when inputs are invalid. Remember, these are front end validations, and additional back end validations are important as a naughty user can easily bypass the front end checks we have above!

Finally, we use the value attribute here, to repopulate the field if, for example, the user submits an invalid password. A small UX tweak.

🤖 Strong Password Auto Generation

Some modern browsers will offer to generate and store a strong password for users. To enable this, be sure to set autocomplete="new-password" on the password field. Also include this same attribute on any password confirmation field.

Svelte Login Form Example: Screen capture shows a login form with an  added drop down in the password field and an offer to generate and sore a strong password.

Here is a snippet in which we set autocomplete="new-password":

      <label for="password">Password</label>
      <input
        bind:value={password}
        on:keydown={() => {
          passwordTouched = true;
        }}
        id="password"
        aria-invalid={passwordError}
        aria-describedby={passwordError ? "password-error" : undefined}
        type="password"
        required
        name="password"
        autocomplete="new-password"
        placeholder="P@s$w0rd"
      />
      {#if errors?.password}
        <small id="password-error" class="error-text">{errors.password}</small>
      {/if}
Enter fullscreen mode Exit fullscreen mode

💪🏽 Password Strength Meter

We mentioned above that OWASP suggest adding a password strength meter. This can help users generate stronger passwords. zxcvbn is a fantastic library for helping here. I guess the name comes from a sequence of keys typically used on English keyboards. As well as measuring password strength, zxcvbn will offer an explanation on why it considers a password to be weak and hints on strengthening it. This is ideal for helping users generate strong passwords.

Svelte Login Form Example: Screen capture shows a login form with a warning that the entered password is similar to a commonly used password and three hints for improvements.  The second hint is to capitalize more that the first letter.

In this project code, we just look at using zxcvbn in the frontend. For a production project, it is worth considering running it on the backend too for password verification. You might also consider running checks using the Have I Been Pwned API, which is a library of known leaked credentials.

Svelte Login Form: Strength Meter Code

First, add some zxcvbn project dependencies:

pnpm add @zxcvbn-ts/core @zxcvbn-ts/language-common \\
  @zxcvbn-ts/language-en
Enter fullscreen mode Exit fullscreen mode

There are other language dictionaries worth considering. Anyway, this is the front end code:

<script lang="ts">
  import { zxcvbn, zxcvbnOptions, type Score } from "@zxcvbn-ts/core";
  import * as zxcvbnCommonPackage from "@zxcvbn-ts/language-common";
  import * as zxcvbnEnPackage from "@zxcvbn-ts/language-en";

  let password = "";
  let passwordTouched = false;

  const { translations } = zxcvbnEnPackage;
  const { adjacencyGraphs: graphs, dictionary: commonDictionary } =
    zxcvbnCommonPackage;
  const { dictionary: englishDictionary } = zxcvbnEnPackage;

  const options = {
    translations,
    graphs,
    dictionary: { ...commonDictionary, ...englishDictionary },
  };
  zxcvbnOptions.setOptions(options);

  $: ({
    score,
    feedback: { warning, suggestions },
  } = zxcvbn(password));

  let strengthDescription = "Low";
  $: switch (score) {
    case 3:
      strengthDescription = "OK";
      break;
    case 4:
      strengthDescription = "Good";
      break;
    case 0:
    case 1:
    case 2:
    default:
      strengthDescription = "Low";
  }
</script>
Enter fullscreen mode Exit fullscreen mode

The password variable is bound to the password input, and in lines 21-24 we use zxcvbn to recompute a score reactively, when password changes. zxcvbn includes a debounce function to make your code more efficient, though we keep things simple here.

The score takes values between 0 and 4, where 3 and 4 indicate unguessable passwords. Notice, the zxcvbn call also yields the warnings and suggestions mentioned above.

While you can use a Svelte each loop to display the suggestions, you might consider an HTML meter element to display the strength meter (thanks to Paweł Błaszczyk for this tip):

<label for="password-strength">Password strength: {strengthDescription}</label>
<meter id="password-strength" value={score} low="1.9" high="2.9" optimum="4" max="4" />
{#if warning}
    <span class="warning"> {warning}</span>
    <ul>
        {#each suggestions as suggestion}
            <li class="alert">{suggestion}</li>
        {/each}
    </ul>{/if}
Enter fullscreen mode Exit fullscreen mode

Svelte Login Form Example: Screen capture shows a login form with a password strength meter reading 75% and text saying the strength is OK.

💯 Svelte Login Form Example: Testing it Out

To see the code in action, clone the repo and install packages. It uses Prisma with an on-disk SQLite database. To get going:

git clone https://github.com/rodneylab/svelte-login-form.git
cd svelte-login-form
pnpm install
cp .env.example .env
pnpm dev
Enter fullscreen mode Exit fullscreen mode

The final, additional step is to send feedback!

🙌🏽 Svelte Login Form Example: Wrapping Up

In this post, we had a look at a Svelte Login form example. More specifically, we saw:

  • why login and signup form UX and security matter;
  • some form UX and security best practices; and
  • how you might add a password strength meter to a Svelte signup form.

Please see the full repo code on the Rodney Lab GitHub repo. For more HTML login form best practices, also see the recent Evil Martians post. I do hope you have found this post useful and can use the code in your own Svelte app. Let me know if you have any suggestions for improvements to the post. Also reach out with ideas on new posts in this area. Drop a comment below or reach out on other channels.

🙏🏽 Svelte Login Form Example: Feedback

If you have found this post useful, see links below for further related content on this site. I do hope you learned one new thing from the video. Let me know if there are any ways I can improve on it. I hope you will use the code or starter in your own projects. Be sure to share your work on Twitter, giving me a mention, so I can see what you did. Finally, be sure to let me know ideas for other short videos you would like to see. Read on to find ways to get in touch, further below. If you have found this post useful, even though you can only afford even a tiny contribution, please consider supporting me through Buy me a Coffee.

Finally, feel free to share the post on your social media accounts for all your followers who will find it useful. As well as leaving a comment below, you can get in touch via @askRodney on Twitter and also askRodney on Telegram. Also, see further ways to get in touch with Rodney Lab. I post regularly on SvelteKit as well as Search Engine Optimization among other topics. Also, subscribe to the newsletter to keep up-to-date with our latest projects.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .