This page documents the public rix/auth API.
Use auth through the unified Rix facade:
#include <rix.hpp>Then access auth with:
rix.authThe auth API provides helpers for:
registration
login
password hashing
sessions
tokens
configuration
memory stores
error handlingThe auth package is:
rix/authFor facade usage, install:
vix add rix/rix
vix installIn vix.app:
deps = [
"rix/rix",
]For independent package usage, install:
vix add rix/auth
vix installIn vix.app:
deps = [
"rix/auth",
]Facade usage:
#include <rix.hpp>Independent usage:
#include <rix/auth.hpp>Most application examples should use the facade.
The auth facade member is:
rix.authExample:
#include <rix.hpp>
int main()
{
auto auth = rix.auth.memory();
auto registered = auth.register_user({
"ada@example.com",
"correct-password"});
return registered.ok() ? 0 : 1;
}rix.auth exposes several helper areas:
rix.auth.memory()
rix.auth.password
rix.auth.config
rix.auth.errorCommon usage:
auto auth = rix.auth.memory();
auto config = rix.auth.config.development();
auto hashed = rix.auth.password.hash("correct-password");
auto error_text = rix.auth.error.to_string(error);Use:
auto auth = rix.auth.memory();This creates an auth service backed by in-memory user and session stores.
Memory auth is useful for:
examples
tests
local development
small demos
temporary applicationsMemory auth does not persist users or sessions after the process exits.
auto config = rix.auth.config.development();
config.set_min_password_length(8);
config.set_session_ttl_seconds(60 * 60 * 24 * 7);
config.set_token_ttl_seconds(60 * 15);
auto auth = rix.auth.memory(config);Use configuration when you want to change password policy, token lifetime, session lifetime, or issuer.
Use:
auto registered = auth.register_user({
"ada@example.com",
"correct-password"});register_user returns an explicit result.
Check it before using the user:
if (registered.failed())
{
rix.debug.eprint(
"auth error:",
rix.auth.error.to_string(registered.error()),
registered.error().message());
return 1;
}Then use:
const auto &user = registered.value();A register request contains:
email
passwordExample:
auto registered = auth.register_user({
"ada@example.com",
"correct-password"});The plain-text password is hashed before storage.
Do not log the plain-text password.
Use:
auto login = auth.login({
"ada@example.com",
"correct-password"});login returns an explicit result.
Check it:
if (login.failed())
{
rix.debug.eprint(
"auth error:",
rix.auth.error.to_string(login.error()),
login.error().message());
return 1;
}Then use:
login.value().user
login.value().session
login.value().tokenA successful login contains:
user
session
tokenExample:
rix.debug.print("user:", login.value().user.email());
rix.debug.print("session:", login.value().session.id());
rix.debug.print("issuer:", login.value().token.issuer());Session ids and token values are sensitive.
Do not print them in production logs.
Use:
auto session = auth.authenticate_session(
login.value().session.id());Check the result:
if (session.failed())
{
rix.debug.eprint(
"auth error:",
rix.auth.error.to_string(session.error()),
session.error().message());
return 1;
}Then:
rix.debug.print("session user id:", session.value().user_id());A session is valid when it exists, is not expired, and is not revoked.
Use:
auto refreshed = auth.refresh_session(session_id);Check it:
if (refreshed.failed())
{
rix.debug.eprint(
"auth error:",
rix.auth.error.to_string(refreshed.error()),
refreshed.error().message());
return 1;
}Then:
rix.debug.print("new expires at:", refreshed.value().expires_at());Refreshing a session extends its expiration according to the configured session lifetime.
Use:
auto status = auth.logout(session_id);Check it:
if (status.failed())
{
rix.debug.eprint(
"auth error:",
rix.auth.error.to_string(status.error()),
status.error().message());
return 1;
}Logout revokes the session.
A revoked session can remain stored, but it cannot be used for authentication.
Use:
auto status = auth.logout_user(user_id);Example:
auto status = auth.logout_user(registered.value().id());
if (status.failed())
{
rix.debug.eprint(
"auth error:",
rix.auth.error.to_string(status.error()),
status.error().message());
return 1;
}This revokes all sessions belonging to the user.
Use:
auto token = auth.issue_token(user_id);Check it:
if (token.failed())
{
rix.debug.eprint(
"auth error:",
rix.auth.error.to_string(token.error()),
token.error().message());
return 1;
}Then read token metadata:
rix.debug.print("user id:", token.value().user_id());
rix.debug.print("issuer:", token.value().issuer());
rix.debug.print("issued at:", token.value().issued_at());
rix.debug.print("expires at:", token.value().expires_at());Do not log raw token values in production.
Password helpers are available through:
rix.auth.passwordCommon helpers:
rix.auth.password.hash(...)
rix.auth.password.verify(...)
rix.auth.password.accepts(...)
rix.auth.password.hasher()Use:
auto hashed = rix.auth.password.hash("correct-password");Check it:
if (hashed.failed())
{
rix.debug.eprint(
"auth error:",
rix.auth.error.to_string(hashed.error()),
hashed.error().message());
return 1;
}Then store:
hashed.value()Do not store plain-text passwords.
Use:
const bool ok = rix.auth.password.verify(
"correct-password",
hashed.value());Wrong passwords return false:
const bool wrong = rix.auth.password.verify(
"wrong-password",
hashed.value());Example:
if (ok && !wrong)
{
rix.debug.print("password verification works");
}Use:
const bool accepted = rix.auth.password.accepts("correct-password");Example:
if (!rix.auth.password.accepts("short"))
{
rix.debug.eprint("password rejected by policy");
}hash also checks the password policy.
Use:
auto hasher = rix.auth.password.hasher();Then:
auto hashed = hasher.hash("correct-password");
const bool ok = hasher.verify(
"correct-password",
hashed.value());With configuration:
auto config = rix.auth.config.production();
auto hasher = rix.auth.password.hasher(config);For most application code, the facade helpers are enough.
Configuration helpers are available through:
rix.auth.configCommon helpers:
rix.auth.config.development()
rix.auth.config.production()Use:
auto config = rix.auth.config.development();Development configuration is useful for examples and local development.
It allows simple register and login flows.
Example:
auto auth = rix.auth.memory(
rix.auth.config.development());Use:
auto config = rix.auth.config.production();Production configuration is stricter.
It can require email verification before login.
Example:
auto auth = rix.auth.memory(
rix.auth.config.production());Use production configuration when building a real application flow.
Common configuration setters include:
config.set_min_password_length(...)
config.set_session_ttl_seconds(...)
config.set_token_ttl_seconds(...)
config.set_issuer(...)
config.set_password_hash_iterations(...)
config.set_password_salt_size(...)
config.set_password_hash_size(...)Example:
auto config = rix.auth.config.development();
config.set_min_password_length(12);
config.set_session_ttl_seconds(60 * 60 * 24 * 7);
config.set_token_ttl_seconds(60 * 15);
config.set_issuer("my-app");
auto auth = rix.auth.memory(config);Error helpers are available through:
rix.auth.errorCommon helpers:
rix.auth.error.to_string(error)
rix.auth.error.is(error, code)Example:
if (registered.failed())
{
const auto &error = registered.error();
rix.debug.eprint(
"auth error:",
rix.auth.error.to_string(error),
error.message());
}Auth error codes include:
rixlib::auth::AuthErrorCode::InvalidInput
rixlib::auth::AuthErrorCode::InvalidEmail
rixlib::auth::AuthErrorCode::InvalidPassword
rixlib::auth::AuthErrorCode::UserNotFound
rixlib::auth::AuthErrorCode::UserAlreadyExists
rixlib::auth::AuthErrorCode::InvalidCredentials
rixlib::auth::AuthErrorCode::InvalidSession
rixlib::auth::AuthErrorCode::SessionExpired
rixlib::auth::AuthErrorCode::InvalidToken
rixlib::auth::AuthErrorCode::TokenExpired
rixlib::auth::AuthErrorCode::InvalidState
rixlib::auth::AuthErrorCode::StoreError
rixlib::auth::AuthErrorCode::UnknownUse error codes for programmatic decisions.
Use messages for diagnostics.
if (rix.auth.error.is(
login.error(),
rixlib::auth::AuthErrorCode::InvalidCredentials))
{
rix.debug.eprint("login failed:", "invalid credentials");
}This lets your app react differently depending on the failure.
Auth APIs use explicit results.
For operations that return a value:
auto result = auth.login({
"ada@example.com",
"correct-password"});
if (result.failed())
{
rix.debug.eprint(
"auth error:",
rix.auth.error.to_string(result.error()),
result.error().message());
return 1;
}
const auto &login = result.value();Never call value() before checking success.
Some operations return a status.
Example:
auto status = auth.logout(session_id);
if (status.failed())
{
rix.debug.eprint(
"auth error:",
rix.auth.error.to_string(status.error()),
status.error().message());
return 1;
}Use:
status.ok()
status.failed()
status.error()A user value exposes user information.
Common methods include:
user.id()
user.email()
user.active()
user.email_verified()Example:
const auto &user = registered.value();
rix.debug.print("id:", user.id());
rix.debug.print("email:", user.email());Do not print password hashes in application output.
A session value exposes session information.
Common methods include:
session.id()
session.user_id()
session.created_at()
session.expires_at()
session.revoked()
session.expired(...)
session.usable(...)Example:
const auto &session = login.value().session;
rix.debug.print("user id:", session.user_id());
rix.debug.print("expires at:", session.expires_at());Session ids are sensitive.
Avoid logging raw session ids in production.
A token value exposes token information.
Common methods include:
token.value()
token.user_id()
token.issuer()
token.issued_at()
token.expires_at()
token.revoked()
token.revoke()
token.expired(...)
token.usable(...)
token.belongs_to(...)
token.issued_by(...)Example:
const auto &token = login.value().token;
rix.debug.print("issuer:", token.issuer());
rix.debug.print("expires at:", token.expires_at());The raw token value is sensitive.
Avoid logging:
token.value()in production.
#include <rix.hpp>
int main()
{
auto auth = rix.auth.memory();
auto registered = auth.register_user({
"ada@example.com",
"correct-password"});
if (registered.failed())
{
rix.debug.eprint(
"auth error:",
rix.auth.error.to_string(registered.error()),
registered.error().message());
return 1;
}
auto login = auth.login({
"ada@example.com",
"correct-password"});
if (login.failed())
{
rix.debug.eprint(
"auth error:",
rix.auth.error.to_string(login.error()),
login.error().message());
return 1;
}
auto session = auth.authenticate_session(
login.value().session.id());
if (session.failed())
{
rix.debug.eprint(
"auth error:",
rix.auth.error.to_string(session.error()),
session.error().message());
return 1;
}
rix.debug.print("authenticated user id:", session.value().user_id());
return 0;
}Run:
vix run auth.cpp#include <rix.hpp>
int main()
{
auto hashed = rix.auth.password.hash("correct-password");
if (hashed.failed())
{
rix.debug.eprint(
"auth error:",
rix.auth.error.to_string(hashed.error()),
hashed.error().message());
return 1;
}
const bool valid = rix.auth.password.verify(
"correct-password",
hashed.value());
const bool invalid = rix.auth.password.verify(
"wrong-password",
hashed.value());
if (!valid || invalid)
{
return 1;
}
rix.debug.print("password verification successful");
return 0;
}#include <rix.hpp>
int main()
{
auto auth = rix.auth.memory();
auto registered = auth.register_user({
"grace@example.com",
"correct-password"});
if (registered.failed())
{
return 1;
}
auto login = auth.login({
"grace@example.com",
"correct-password"});
if (login.failed())
{
return 1;
}
const auto session_id = login.value().session.id();
auto refreshed = auth.refresh_session(session_id);
if (refreshed.failed())
{
return 1;
}
auto logout = auth.logout(session_id);
if (logout.failed())
{
return 1;
}
auto after_logout = auth.authenticate_session(session_id);
return after_logout.failed() ? 0 : 1;
}#include <rix.hpp>
int main()
{
auto auth = rix.auth.memory();
auto registered = auth.register_user({
"linus@example.com",
"correct-password"});
if (registered.failed())
{
return 1;
}
auto token = auth.issue_token(
registered.value().id());
if (token.failed())
{
return 1;
}
rix.debug.print("issuer:", token.value().issuer());
rix.debug.print("expires at:", token.value().expires_at());
return 0;
}#include <vix.hpp>
#include <rix.hpp>
int main()
{
vix::App app;
auto auth = rix.auth.memory();
app.post("/register", [&](vix::Request &, vix::Response &res) {
auto registered = auth.register_user({
"ada@example.com",
"correct-password"});
if (registered.failed())
{
res.status(400).json({
"ok", false,
"error", rix.auth.error.to_string(registered.error()),
"message", registered.error().message()});
return;
}
res.json({
"ok", true,
"email", registered.value().email()});
});
app.run();
return 0;
}For durable applications, use database-backed stores instead of memory stores.
Create a Vix app:
vix new rix-auth-api --app
cd rix-auth-apiAdd Rix:
vix add rix/rix
vix installMake sure vix.app contains:
deps = [
"rix/rix",
]Use in src/main.cpp:
#include <rix.hpp>Build and run:
vix build
vix runCreate a file:
mkdir -p ~/rix-auth-api
cd ~/rix-auth-api
touch auth.cppAdd:
#include <rix.hpp>
int main()
{
auto auth = rix.auth.memory();
return 0;
}Run:
vix run auth.cppIf Rix is not available globally:
vix install -g rix/rix
vix run auth.cppInstall only auth:
vix add rix/auth
vix installIn vix.app:
deps = [
"rix/auth",
]Then include:
#include <rix/auth.hpp>Use independent package APIs when you intentionally do not want the unified facade.
For most documentation and application examples, prefer:
#include <rix.hpp>and:
rix.authDo not log:
plain-text passwords
password hashes
raw token values
session idsUse HTTPS in production.
Use durable stores for real user accounts.
Use stricter configuration for production.
Keep token lifetimes short.
Keep session lifetimes intentional.
Require email verification when your application needs it.
If your code uses:
#include <rix.hpp>install:
vix add rix/rix
vix installWrong:
packages = [
"rix/rix",
]Correct:
deps = [
"rix/rix",
]deps is for Vix Registry packages.
packages is for CMake package discovery.
Wrong:
auto login = auth.login({
"ada@example.com",
"correct-password"});
rix.debug.print(login.value().user.email());Correct:
auto login = auth.login({
"ada@example.com",
"correct-password"});
if (login.failed())
{
return 1;
}
rix.debug.print(login.value().user.email());Avoid printing:
passwords
password hashes
tokens
session idsMemory auth is not durable.
When the process exits, users and sessions are gone.
Use database-backed stores for real applications.
Production config can require email verification before login.
For simple examples, use:
auto auth = rix.auth.memory();or:
auto auth = rix.auth.memory(
rix.auth.config.development());A session is server-side authentication state.
A token is a short-lived value issued for a user.
They have separate lifetimes:
config.set_session_ttl_seconds(...);
config.set_token_ttl_seconds(...);Create auth:
auto auth = rix.auth.memory();Register:
auto registered = auth.register_user({
"ada@example.com",
"correct-password"});Login:
auto login = auth.login({
"ada@example.com",
"correct-password"});Authenticate session:
auto session = auth.authenticate_session(
login.value().session.id());Hash password:
auto hashed = rix.auth.password.hash("correct-password");Verify password:
const bool ok = rix.auth.password.verify(
"correct-password",
hashed.value());Issue token:
auto token = auth.issue_token(user_id);Always check failed() before using value().
For project usage:
vix add rix/rix
vix installand keep:
deps = [
"rix/rix",
]Continue with the CSV API.
Next: CSV API