# Announcing Magnetar - Authentication to power your applications

### Magnetar is the authentication engine inside Suprnova. It handles passwords, passkeys, two-factor codes, magic links, and sign-in with Google, Apple, Facebook, X, and TikTok, and it is built around one idea: auth doesn't have to be confusing or hard.

Every web application needs to answer the same question thousands of times a day: is this really the person they say they are? Getting that wrong is how accounts get taken over, and most of the ways it goes wrong are not exotic. They are small gaps between features that were each built correctly on their own.

Magnetar is the authentication engine inside Suprnova. It ships with the framework, you turn it on with a few lines in your bootstrap, and from then on passwords, passkeys, two-factor codes, magic links, sign-in with Google, Apple, Facebook, X, and TikTok, remember-me, email verification, and password reset all run through one engine that was designed to close those gaps.

```rust
use suprnova::{DB, MagnetarConfig, PasskeyConfig, init_magnetar};

DB::init().await?;
let db = DB::connection()?;

let config = MagnetarConfig::from_sea_orm(db.inner().clone())
    .passkey_config(PasskeyConfig {
        rp_id: "example.com".to_owned(),
        rp_origin: "https://example.com".to_owned(),
    });

init_magnetar(config).await?;
```

That is the whole installation. Magnetar checks that your application key is set, creates or upgrades its tables, and publishes the password and passkey engines in one step. If any part of that setup is invalid, nothing is written to the database. Then `Auth::password().register(...)` and `Auth::password().authenticate(...)` work, and the rest of the framework's auth facades sit on top.

## Why we built it

Suprnova already had the Laravel-shaped auth surface: guards, a user provider, `Auth::login`, password reset. What it did not have was a single place where the security rules lived. Password hashing was in one module, session revocation in another, "what happens when someone changes their password" in a third. Each piece was fine. The joints between them were where an attacker would look.

So we built the joints as the product. Magnetar is a separate crate in the Suprnova workspace, with no HTTP, no cookies, and no knowledge of your routes. The framework owns those. Magnetar owns the decisions: who is allowed to start a session, when every session for a user stops being valid, what a password check is allowed to reveal, and what has to happen atomically when someone proves they own an email address.

## What it does

Here is what is implemented today, not planned. Each of these is a working service with its own tests.

- **Passwords**, with lockout after repeated failures and a hashing policy that upgrades old hashes automatically.
- **Passkeys** (WebAuthn), for sign-in without a password.
- **Two-factor codes** (TOTP) with recovery codes.
- **Magic links** sent by email.
- **Sign-in with Google, Apple, Facebook, X, and TikTok**, plus an OAuth engine that also handles device authorization for TVs and CLIs, refresh tokens, revocation, and a token cache for calling third-party APIs on the user's behalf.
- **Sessions**, either opaque tokens stored in the database or signed JWTs, plus remember-me.
- **Email verification** and **password reset**.
- **Linked accounts**, so one person can sign in several ways.
- **A migration engine** for bringing an existing user table into Magnetar without rewriting your IDs.

Magnetar does not send email. It produces the message shapes (verification, reset, password-changed, magic link) and your application sends them through Suprnova's mail system, which means your templates and your provider stay yours.

### Everything runs in your application

There is no third-party authentication service behind Magnetar. It is a library that runs inside your process against your own database. Passwords are hashed and checked on your server. Passkeys are registered and verified there. Magic-link and reset tokens are minted, encrypted, and consumed there. Sessions live in your database or in JWTs you sign. When a user enables two-factor, Magnetar generates the secret, the `otpauth://` link, and the QR code image itself, in-process, so the user scans it straight off your page into Google Authenticator, 1Password, or whatever they use. The secret never leaves your box to get drawn.

The only outside parties are the ones you choose: the social sign-in providers you enable, Redis if you use it for rate limiting, and the mail provider you already have. Nothing about identity is outsourced by default.

## How the plugins work

Every sign-in method in Magnetar is a plugin: password, passkey, two-factor, magic link, email verification, password management, device authorization, and one plugin per social provider. Each plugin is mirrored one-to-one by a Cargo feature, so a method you don't use costs nothing in your binary. The first-party plugins are built on the same public SDK that third-party authors get. They have exactly one privilege the SDK does not hand out: at the moment a user proves who they are, a first-party plugin may mint a verified principal. Everything after that point is the same for everyone.

A plugin is a small, explicit contract:

- **It declares its routes.** Each route has a method, a path template, and a stable name like `password.login`, plus the feature that owns it. The framework mounts them. A plugin cannot register a route the host did not agree to.
- **It validates itself at boot.** `init` runs once with the host's configuration. If a plugin's settings are wrong, the application fails to start rather than failing a user later.
- **It can run before every request.** A plugin's `before_request` hook can let a request continue, answer it directly, or ask the host to resolve a bearer token. That is how API token authentication is wired in: the plugin recognizes the credential, the host decides what session it maps to.
- **It handles its own requests.** `handle` receives a request and returns a response plus a list of typed effects.
- **It can subscribe to lifecycle events.** After a mutation commits, plugins receive `UserCreated`, `UserDeleted`, `SessionCreated`, or `SessionDeleted` with a stable mutation ID, so a retry never fires twice.

The interesting part is what a plugin is given and what it is not. Through its context, a plugin can read and write its own tokens and ceremonies, ask questions about sessions, call the abuse limiter, encrypt values, hand a mail message to the host, make outbound HTTP calls, and generate links. It is not given a way to create a session.

Here is how a login actually finishes. The password plugin checks the credential, then asks the host's factor gate whether this sign-in may become a session. The gate answers one of two ways: session allowed, with a grant the host issued, or factor required, with a pointer to the challenge the user still has to pass (a TOTP code, for example). The plugin puts that grant into its response as an `EstablishSession` effect, and the framework turns the effect into a cookie or a bearer token. The plugin never touched a session; it carried a grant the host minted.

The other effects follow the same pattern. `ClearSession`, `IssueRemember`, `Redirect`, `SetHeader`, `SetStatus`, and `Json` are descriptions of what should happen, and the framework decides how they happen for its carrier. That is what lets the same plugin serve a cookie-based web app and a bearer-token API without knowing which one it is in.

If you want to add a sign-in method Magnetar doesn't ship, you write one of these. You get the same storage, limiter, encryption, mail, and HTTP boundaries the first-party plugins use, and the same wall in front of session minting.

## The guarantees, in plain language

This is the part that matters. These are not settings you can forget to enable. They are how the code is written, and each one has a test that fails if it stops being true.

### Change your password and every old session is invalidated

Every user has a session assigned id on their account that Magnetar calls the `auth epoch`. Every session, remember-me cookie, and JWT records the epoch it was issued under. When you reset your password, the epoch is assigned inside the same database transaction that writes the new hash. Any session still carrying the old epoch is rejected the next time it shows up. There is no background job to run and no cache to clear.

Logging out of one browser does not touch the epoch. Only you, from one device, are affected. That distinction is deliberate.

### Checking a password takes the same time whether or not you exist

A classic leak: the server responds faster for an email it has never seen, because there is no hash to check. Magnetar's verifier does one bcrypt computation and one Argon2 computation on every attempt, no matter what. If the account exists, its real hash is checked in whichever format it is stored in and a warmed dummy is run in the other. If the account does not exist, both dummies run. From the outside, "wrong password", "locked account", and "no such user" cost the same and say the same thing.

The Argon2id lane is the target. If a user's hash is still bcrypt from an older system, it is upgraded after a successful login. Bcrypt is never used to create new hashes, and a failed upgrade never turns a correct password into a failed login.

### The first proof of your mailbox wipes out squatters

Suppose someone registers with your email address before you do. They cannot verify it, but they might set up a password, enroll a two-factor device, or link a social account, hoping you will inherit it. Magnetar treats the first successful proof of mailbox ownership on an unverified account (a password reset, a magic link, or a verified email from a sign-in provider) as a clean slate. In one transaction it deletes that account's provider tokens, linked accounts, auth methods, and two-factor enrollment, revokes every session and remember-me token, writes your new credential, and marks the email verified. The squatter's setup does not survive the moment you show up.

### Signing in with Google never silently attaches to an existing account

If you already have an account with `you@example.com` and someone signs in through a provider that reports the same address, Magnetar does not link them. The default policy requires an explicit link by the authenticated owner. An unverified provider email is treated as if it were absent, so it never even reaches the matching step.

### Two-factor is a factor, not a door

A correct TOTP code can never start a session by itself. It only satisfies a gate on a session that a real sign-in method already opened. Codes are checked in constant time, each time step can be claimed once so a code cannot be replayed, and recovery-code lookups take the same time whether or not there is a match.

### Rate limiting fails closed

Magnetar's abuse limiter is a contract, and the contract says a backend failure is an error, never an allow. The shipped Redis driver honors that, and its keys are hashes, so raw email addresses and tokens never appear in Redis. If the limiter is down, sending reset links and registering new accounts stops until it is back, rather than quietly becoming unlimited.

### Only one place can mint a session

Providers and plugins, including the first-party ones, cannot create a session. There is exactly one internal issuer, it has no public constructor, and the approval it requires is private to the crate. A plugin can ask questions about sessions. It cannot make one.

## Bringing your existing users

Most applications already have a `users` table. Magnetar does not require you to move off it.

If your app uses Suprnova's Eloquent user provider and your user model implements `MustVerifyEmail` and `CanResetPassword`, email verification and password reset for verified accounts work without Magnetar installed at all. This is what Suprnova's own dogfood application does. Magnetar becomes required when you want the clean-slate behavior above for unverified accounts, or when you want Magnetar to own credentials and sessions.

If you do want to move, the migration engine reads your existing table shape, asks you to confirm it, does a dry run, and then applies. It never invents new public identifiers for your users. Existing bcrypt hashes keep working on day one and upgrade to Argon2id as people log in. If two legacy rows normalize to the same email, the migration lists every owner and stops before writing anything.

## What it will not do for you

Magnetar is deliberately narrow about ownership. It does not define your routes, your cookies, or your mail templates. It does not send unprompted product email. It does not decide which pages require a verified email; that stays in your middleware. It does not provide an in-memory rate limiter for production, because a limiter that lives in one process is not a limiter. And it does not model multi-tenancy; that is an application concern.

## Getting started

Magnetar ships with Suprnova v1.3.1. The bootstrap chapter of the manual walks through `init_magnetar`, the passkey configuration, rate-limiting setup, and the OAuth provider plugins. The API starter kit uses Magnetar's `app_users` schema out of the box; the full-stack kit uses the provider fallback and can adopt Magnetar when you need it.

We built Magnetar because authentication is the part of every application that everyone rewrites and nobody wants to own. Now Suprnova owns it, and the rules are in code where a test can hold them.