Skip to main content

Login Widget

When I started SpartanAuth, I had a simple obsession: authentication should be easy to do correctly. Complexity is where security bugs and abandoned sign-ins both hide. Today I want to talk about the login widget.

Why build a widget?

TLDR: usability, branding, and making the secure path the easy path.

Businesses lose real money when people cannot sign in. “About a third of online purchases are abandoned at checkout because consumers cannot remember their passwords,” from a study conducted jointly by MasterCard and the University of Oxford (source). That is a big reason I care about helping apps move away from relying on passwords.

~⅓
Of online purchases abandoned at checkout over forgotten passwords

Replacing passwords with stronger authentication can be expensive, complicated, error-prone, and hard to use. SpartanAuth exposes an API so you can build your own login page — but I also wanted a complete path that is kind to both end users and the developers wiring it up.

User experience matters. So does branding. A login screen is often the front door of a product; it should feel like your app, not a generic detour.

So I built a login widget with the factors SpartanAuth supports, configurable enough to match your look and feel.

Choosing a tech

Shipping third-party UI into someone’s app is a trust exercise. I wanted the widget stack to be reliable, fast, and small. Frontend framework debates aside, the last decade of competition has been great for bundle size and performance — and I wanted those gains.

I set three criteria. The technology had to:

  • be simple to implement in any web environment
  • have a minimal bundle size when delivered to the end user
  • be a leader in performance
Simple
Drop into any web environment
Small
Minimal bundle for end users
Fast
Performance as a first-class goal

My first prototype was in Vue. Reactive UI is lovely, and the prototype was decent — but Vue is not ideal when you are shipping a single custom element. They even say explicitly that “it is not ideal to use Vue if you are shipping a single custom element”. So I kept looking.

At the suggestion of my friend Christopher Bradshaw, I found SolidJS. This blog post is still one of the clearest write-ups I have seen on compilers, bundle size, and performance. Reactive programming on top was icing.

Solid checked the boxes: near-vanilla JS performance, a bias toward less client JS, TypeScript support, and a tiny final bundle. And yes — it could ship as something developers drop in easily.

Solid has a library aimed at custom elements: Solid Element.

Results

The early Solid prototype was promising. A custom login page could look like this:

<script type="module" crossorigin src="/assets/index.2157afe0.js"></script>

and

<spartan-login start-mode="webAuthn" locale="en" redirect="/app.html"></spartan-login>
2 lines
To embed a full login experience
~17 KB
Gzipped bundle in the early Solid prototype

Bundle size was already reasonable, with room to improve:

index.668c492a.js            44.63 KiB / gzip: 16.70 KiB

That build included i18n, and the multi-locale result looked like this:

Four copies of the login widget each with a different language.

Customization started simple and powerful: pass CSS through a styles attribute and it applies. More knobs can come later; full CSS control is already a lot.

Login widget with the button stylized to match with a background of trees.

Why the widget is open source

This matters to me: the login widget library is open source. You should be able to inspect what you embed. SpartanAuth the service is a product I am building and running for real apps — including several of my own — but I want the client piece developers drop into a page to be transparent.

Open widget
Inspect what you embed — the login library is open source

Next steps

The widget began as a focused prototype and grows as the backend gains features. If you want to follow along, use the RSS feed or the newsletter below. And if you are building something that needs auth, I would love for you to try SpartanAuth.