An experimental Single Sign-On platform and OIDC provider built in Rust that doesn't have shared secrets (like passwords)
- Rust 63.6%
- JavaScript 32.6%
- Just 3.6%
- CSS 0.2%
Stuff left to setup
- Cryptography to verify the signatures
- OIDC server library
Current status
- Research
- List of features
- Define current feature scope
- Wireframes
- Database schema
- Define the project's architecture
- Define the main challenges
- Choose solutions for each challenge
- Project setup
- Theme
- Database setup
- Code the rest of the damn owl
- Refactoring
- Feedback
Tech stack
- Web framework:
axumwithtokio - Authentication: Flows described below + Copenhagen Book
- Authorization:
axum-login - Sessions:
tower-sessions - Persistence:
sqlxwithsqlitefeature - Templating:
maud - Styling: TailwindCSS
- Configuration:
dotenvy - Error handling:
thiserror - Static file serve:
static-serve - OIDC server:
openidconnect, Copenhagen book and the official OIDC Core and Discovery spec - Random generator:
rand - Captcha system: ??? (should not be an external service and should use only PoW)
- Cryptography: Built-in
cryptoWeb API of browsers for client. Anded25519-dalekfor the backend cryptography.- Lots of questions on that point, especially for the key management on the browser...
Features
- Create an account (register public key)
- Secure key using password (encrypt private key)
- Login into an account
- Link a device with current
- Backup account keys
- Restore account using encrypted backup
- Get user's info using OIDC
- Would be also nice to have captcha for registration and/or invite code
How will authentication work here?
Registration Flow
- The user asks for login
- The server returns the page with a challenge (random string) + PoW challenge
- The browser generates a private and public key and signs the challenge + do the PoW challenge
- The browser prompts the user for a password to encrypt the private key and store the private and public key in its storage
- The browser sends (POST) the challenge, signature and public key to the server (along with the PoW response)
- The server verifies the PoW response, that the challenge exists and the signature is valid then if no user exists for that public key, it creates one
- The server create a session for the user
Authentication flow
- The user asks for login
- The server returns a page with a challenge (random string)
- The browser prompts the user for a password to decrypt the private key
- The browser signs the challenge with the private key and sends it
- The browser sends (POST) the challenge, signature and public key to the server
- The server verifies the challenge exists and signature is valid then retrieve the user corresonding to that key from the db
- The server creates a session for the user
Link a device
- The user follows the registration flow
- The user says they already have an account on another device
- The server redirects the user to a /link/{code} URL that auto-refresh
- The user scans the QR code (or go on the /verify/{code} link) with their other device
- The user confirms their action on the other device
- The server stores the code linked to their account
- When the device 1 refreshes, the server looks for that code and if found, links their key to that account
Endpoints
- GET /authorize → OIDC entrypoint, either redirects back if session exists, or return login page with challenge
- POST /authorize → submit challenge with signature and key
- GET /link/{code} → link a device to an account (device that requests)
- GET /verify/{code} → link a device to an account (already connected device that confirms)
- POST /token → exchange authorization code with token (and therefore user's info)
- GET /.well-known/openid-configuration → returns the list of endpoints for OIDC