rix/auth is the official authentication library for Rix and Vix.cpp applications.
It provides a small production-oriented authentication layer for C++ apps:
- user registration
- login
- password hashing
- server-side sessions
- short-lived auth tokens
- logout
- session validation
- memory stores for tests and small apps
- database stores for durable production usage
- explicit
AuthResult<T>andAuthStatuserror handling
rix/auth is built to use Vix modules instead of reinventing low-level foundations:
vix::cryptofor secure random ids and password hashing helpersvix::validationfor input validationvix::timefor timestampsvix::dbfor persistent database-backed stores
Add the package to your Vix project:
vix add rix/authThen include it:
#include <rix/auth/Auth.hpp>#include <rix/auth/Auth.hpp>
#include <rix/auth/AuthConfig.hpp>
#include <rix/auth/stores/MemorySessionStore.hpp>
#include <rix/auth/stores/MemoryUserStore.hpp>
#include <iostream>
#include <string>
int main()
{
rixlib::auth::MemoryUserStore users;
rixlib::auth::MemorySessionStore sessions;
auto config = rixlib::auth::AuthConfig::development();
rixlib::auth::Auth auth{
users,
sessions,
config};
auto registered_user = auth.register_user(
rixlib::auth::RegisterRequest{
"ada@example.com",
"correct-password"});
if (registered_user.failed())
{
std::cerr << registered_user.error().message() << '\n';
return 1;
}
auto login = auth.login(
rixlib::auth::LoginRequest{
"ada@example.com",
"correct-password"});
if (login.failed())
{
std::cerr << login.error().message() << '\n';
return 1;
}
std::cout << "user: " << login.value().user.email() << '\n';
std::cout << "session: " << login.value().session.id() << '\n';
std::cout << "token issuer: " << login.value().token.issuer() << '\n';
return 0;
}Run:
vix run examples/basic.cpp#include <rix/auth/Auth.hpp>The main class is:
rixlib::auth::AuthIt exposes:
register_user(...)login(...)logout(...)logout_user(...)authenticate_session(...)refresh_session(...)issue_token(...)config()password_hasher()
Use AuthConfig to configure authentication behavior.
auto config = rixlib::auth::AuthConfig::production();
config.set_min_password_length(12);
config.set_session_ttl_seconds(60 * 60 * 24 * 7);
config.set_token_ttl_seconds(60 * 10);
config.set_issuer("my-app");
config.set_require_email_verification(true);
config.set_rotate_sessions(true);auto config = rixlib::auth::AuthConfig::development();Development defaults are useful for local apps, examples, and tests.
auto config = rixlib::auth::AuthConfig::production();Production defaults are stricter and should be preferred for real applications.
auto result = auth.register_user(
rixlib::auth::RegisterRequest{
"ada@example.com",
"correct-password"});
if (result.failed())
{
std::cerr << result.error().message() << '\n';
return 1;
}
const auto &user = result.value();Registration validates the email, validates the password policy, hashes the password, creates the user, and stores it through the configured UserStore.
Email addresses are normalized before validation, lookup, and persistence.
The built-in policy trims leading/trailing whitespace and lower-cases the full
address. Provider-specific aliases such as Gmail dots or plus-addressing are
not interpreted by rix/auth.
auto result = auth.login(
rixlib::auth::LoginRequest{
"ada@example.com",
"correct-password"});
if (result.failed())
{
std::cerr << result.error().message() << '\n';
return 1;
}
const auto &login = result.value();
std::cout << login.user.email() << '\n';
std::cout << login.session.id() << '\n';
std::cout << login.token.value() << '\n';A successful login returns:
rixlib::auth::LoginResultIt contains:
User user;
Session session;
Token token;auto session = auth.authenticate_session(session_id);
if (session.failed())
{
std::cerr << session.error().message() << '\n';
return 1;
}
std::cout << "session user: "
<< session.value().user_id()
<< '\n';A usable session must be:
- valid
- not revoked
- not expired
auto refreshed = auth.refresh_session(session_id);
if (refreshed.failed())
{
std::cerr << refreshed.error().message() << '\n';
return 1;
}Refreshing updates the session expiration and last_seen_at.
auto status = auth.logout(session_id);
if (status.failed())
{
std::cerr << status.error().message() << '\n';
return 1;
}Logout revokes the session instead of deleting it.
auto status = auth.logout_user(user_id);
if (status.failed())
{
std::cerr << status.error().message() << '\n';
return 1;
}This is useful after password changes, account compromise, or admin actions.
auto token = auth.issue_token(user_id);
if (token.failed())
{
std::cerr << token.error().message() << '\n';
return 1;
}Tokens are short-lived values attached to a user id and issuer.
Token is a non-persisted bearer-token value returned by login and
issue_token(). The server-side revocation authority in rix/auth is the
SessionStore; token revocation on the Token model is only local object
state unless an application adds its own token persistence layer. For
server-verifiable logout/revocation, authenticate the stored session id and
keep token lifetimes short.
rix/auth does not throw for normal authentication failures.
It uses:
AuthResult<T>AuthStatusAuthErrorAuthErrorCode
Example:
auto result = auth.login(
rixlib::auth::LoginRequest{
"ada@example.com",
"wrong-password"});
if (result.failed())
{
if (result.error().code() == rixlib::auth::AuthErrorCode::InvalidCredentials)
{
std::cerr << "invalid credentials\n";
}
}Common error codes include:
noneinvalid_inputinvalid_emailinvalid_passworduser_not_founduser_already_existsinvalid_credentialsinvalid_sessionsession_expiredsession_revokedinvalid_tokentoken_expiredinvalid_statestore_errorcrypto_errorconfiguration_errorunknown
rix/auth separates authentication logic from storage.
The main interfaces are:
UserStoreSessionStore
Available store implementations:
MemoryUserStoreMemorySessionStoreDbUserStoreDbSessionStore
Memory stores are useful for tests, examples, and small temporary apps.
#include <rix/auth/stores/MemoryUserStore.hpp>
#include <rix/auth/stores/MemorySessionStore.hpp>
rixlib::auth::MemoryUserStore users;
rixlib::auth::MemorySessionStore sessions;
rixlib::auth::Auth auth{
users,
sessions,
rixlib::auth::AuthConfig::development()};Memory stores do not persist data after the process exits.
Database stores are intended for durable applications.
#include <rix/auth/Auth.hpp>
#include <rix/auth/stores/DbUserStore.hpp>
#include <rix/auth/stores/DbSessionStore.hpp>
#include <vix/db/Database.hpp>
int main()
{
auto database = vix::db::Database::sqlite("data/auth.db");
rixlib::auth::DbUserStore users{database};
rixlib::auth::DbSessionStore sessions{database};
rixlib::auth::Auth auth{
users,
sessions,
rixlib::auth::AuthConfig::production()};
return 0;
}By default, database stores create their required tables automatically.
DbUserStore uses:
rix_auth_users
DbSessionStore uses:
rix_auth_sessions
The stores create the schema automatically when constructed with create_schema = true.
rixlib::auth::DbUserStore users{database, true};
rixlib::auth::DbSessionStore sessions{database, true};Automatic schema creation is explicit and inspectable:
rixlib::auth::DbUserStore users{database};
if (!users.ready())
{
std::cerr << users.schema_status().error().message() << '\n';
return 1;
}Pass create_schema = false when migrations or an application bootstrap step
owns schema creation:
rixlib::auth::DbUserStore users{database, false};
rixlib::auth::DbSessionStore sessions{database, false};The database unique constraints on user id and email are the final authority.
The stores keep pre-checks for friendly errors, but insertion-time unique
collisions are still reported as AuthErrorCode::UserAlreadyExists.
Vix currently exposes vix::db::Database::transaction(Fn) for code that owns
all database writes in one callback. Auth::login() works through abstract
UserStore and SessionStore interfaces, which may be backed by different
systems, so rix/auth does not pretend to wrap those calls in a database
transaction. Instead, login generates all fallible ids/tokens before session
persistence, so a later token-generation failure cannot leave an orphaned
session.
Use Auth for normal application code.
auto result = auth.register_user(...);PasswordHasher is available for lower-level usage and tests:
rixlib::auth::PasswordHasher hasher;
auto hash = hasher.hash("correct-password");
if (hash.ok())
{
bool valid = hasher.verify("correct-password", hash.value());
}Password hashes are encoded and must never be returned to clients or logged.
rixlib::auth::UserFields include:
- id
- password hash
- email verification state
- active state
- created timestamp
- updated timestamp
Useful methods:
valid()has_id(...)has_email(...)active()email_verified()
rixlib::auth::SessionFields include:
- id
- user id
- created timestamp
- expiration timestamp
- last seen timestamp
- revoked state
Useful methods:
valid()belongs_to(...)expired(...)usable(...)refreshable(...)refresh(...)revoke()
rixlib::auth::TokenFields include:
- value
- user id
- issuer
- issued timestamp
- expiration timestamp
- revoked state
Useful methods:
valid()belongs_to(...)matches(...)expired(...)usable(...)revoke()
Build and run tests with Vix:
vix testsThe test suite covers:
- users
- sessions
- tokens
- password hashing
- memory user store
- memory session store
- auth registration
- login
- logout
- session authentication
- token creation
include/rix/auth/
├── Auth.hpp
├── AuthConfig.hpp
├── AuthError.hpp
├── AuthResult.hpp
├── PasswordHasher.hpp
├── Session.hpp
├── SessionStore.hpp
├── Token.hpp
├── User.hpp
├── UserStore.hpp
├── Version.hpp
└── stores/
├── DbSessionStore.hpp
├── DbUserStore.hpp
├── MemorySessionStore.hpp
└── MemoryUserStore.hpp
src/
├── Auth.cpp
├── AuthConfig.cpp
├── AuthError.cpp
├── PasswordHasher.cpp
├── Session.cpp
├── SessionStore.cpp
├── Token.cpp
├── User.cpp
├── UserStore.cpp
├── Version.cpp
└── stores/
├── DbSessionStore.cpp
├── DbUserStore.cpp
├── MemorySessionStore.cpp
└── MemoryUserStore.cpp
tests/
├── AuthTests.cpp
├── MemorySessionStoreTests.cpp
├── MemoryUserStoreTests.cpp
├── PasswordHasherTests.cpp
├── SessionTests.cpp
├── TokenTests.cpp
└── UserTests.cpp
examples/
└── basic.cpp
Use AuthConfig::production() for real applications.
Do not log:
- plain-text passwords
- password hashes
- session ids
- token values
Use durable database stores when sessions must survive restart.
Use HTTPS when sending sessions or tokens over the network.
Keep password hashing and token generation inside rix/auth instead of implementing them in application code.
Current version:
rixlib::auth::version()Current package version:
0.1.0
MIT