Skip to content

patte/axum-solid-playground

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

52 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

axum-solid-playground

Test your passkeys at: https://axum-solid-playground.fly.dev

Features:

Playground to learn:

  • how to combine a rust axum backend with a solidJS frontend?
  • how to authenticate users with discoverable passkeys? and what's the user experience in different browsers?
  • how to manage a session on the server with persistence and sync to the js client (on first render) (MVP)? - async sqlite in rust, yes please #no_orm?
  • how cool is litefs and how to (ab)use it?
  • how to have fun, go light and fast, with a small (<10MB) single standalone binary, that uses <100MB RAM idle.
  • ... all PRs welcome 💓
  • ... and all issues too 🤗

Screenshot 2024-02-07 at 23 10 20
-GitHub Copilot

actually... Screenshot 2024-02-07 at 23 11 58

Development

Copy .env.example to .env:

cd server
cp .env.example .env
cd ..

The rust backend includes a dev proxy for the frontend, so that the host and port of the fe and be is the same, no CORS issues arise, increased dev prod parity, good dev-ex with hot reloading.

In one terminal, run vite:

cd client
npm install
npm run dev

In another terminal, run the backend server:

cd server
cargo watch -x "run --features dev_proxy"

Open http://localhost:3000 to view it in your browser.

Prod

Local

axum-embed is used to embed the frontend into the backend. For single binary niceness.

cd client
npm run build
cd ..
cargo build --release
./target/release/axum-solid-playground

The resulting binary is ~8MB.

fly.io

volume

Create volume initially:

fly launch --no-deploy

# if no volume created during initial launch:
fly volumes create playground --region ams --size 3

envs

Set before the first deploy:

fly secrets set \
RP_ID=axum-solid-playground.fly.dev \
RP_ORIGIN=https://axum-solid-playground.fly.dev \
RP_NAME=axum-solid-playground \
DATABASE_URL=sqlite:///data/playground.db

deploy

fly deploy

image size: 104 MB (but as our binary is only ~8MB, this is what needs to be pushed in most cases)

add clones in other regions

Currently there is only one database on one volume (in ams). Litefs, which would enable distributed SQLite, was removed again, mainly to keep things simple and the limitations with websockets . Only one instance can be run at a time.

remove:

fly machine ls
fly m destroy <id>
fly volumes ls
fly volumes destroy <id>

Docs

Auth

SignUp and SignIn are implemented with passkeys with webauthn-rs.

tower-sessions with a custom RusqliteStore is used for session management.

The session is used for the passkey dance as well as to remember the authenticated user. A cookie authenticated_user_js (http_only=false) is set on successful signin so that the js frontend knows the user is authenticated and can render appropriatly on first load. This cookie is only informative for the client and not used to determine if the user is authenticated on the server. No auth decision on the server is based on the cookie.

The session are rolled every minute (see: roll_expiry_mw). This also keeps the informative cookie fresh.

Browsers

Chrome (local) passkeys can be managed at chrome://settings/passkeys.

Firefox and Safari on MacOS save them in the system keychain, which can be managed in Settings -> Passwords.