Memory Register and Login
This example shows how to register a user, log in, and authenticate a session with rix/auth.
The example uses the public Rix facade:
#include <rix.hpp>and accesses auth through:
rix.authIt uses an in-memory auth store, so it is useful for examples, tests, and local development.
Create the file
mkdir -p ~/rix-auth-memory-example
cd ~/rix-auth-memory-example
touch memory_register_login.cppAdd:
#include <rix.hpp>
int main()
{
rix.debug.print("== rix/auth memory register and login ==");
auto auth = rix.auth.memory();
auto registered = auth.register_user({
"ada@example.com",
"correct-password"});
if (registered.failed())
{
const auto &error = registered.error();
rix.debug.eprint(
"auth error:",
rix.auth.error.to_string(error),
error.message());
return 1;
}
rix.debug.print("registered user");
rix.debug.print("id:", registered.value().id());
rix.debug.print("email:", registered.value().email());
auto login = auth.login({
"ada@example.com",
"correct-password"});
if (login.failed())
{
const auto &error = login.error();
rix.debug.eprint(
"auth error:",
rix.auth.error.to_string(error),
error.message());
return 1;
}
rix.debug.print("----------------------------------------");
rix.debug.print("login successful");
rix.debug.print("user:", login.value().user.email());
rix.debug.print("session:", login.value().session.id());
rix.debug.print("token issuer:", login.value().token.issuer());
auto session = auth.authenticate_session(
login.value().session.id());
if (session.failed())
{
const auto &error = session.error();
rix.debug.eprint(
"auth error:",
rix.auth.error.to_string(error),
error.message());
return 1;
}
rix.debug.print("----------------------------------------");
rix.debug.print("OK:", "session authenticated");
rix.debug.print("session user id:", session.value().user_id());
return 0;
}Run it:
vix run memory_register_login.cppIf Rix is not available yet for single-file usage:
vix install -g rix/rix
vix run memory_register_login.cppExpected output shape:
== rix/auth memory register and login ==
registered user
id: user_...
email: ada@example.com
----------------------------------------
login successful
user: ada@example.com
session: session_...
token issuer: rix/auth
----------------------------------------
OK: session authenticated
session user id: user_...What this example does
The example creates an auth service with memory stores:
auto auth = rix.auth.memory();It registers a user:
auto registered = auth.register_user({
"ada@example.com",
"correct-password"});It logs the user in:
auto login = auth.login({
"ada@example.com",
"correct-password"});It authenticates the created session:
auto session = auth.authenticate_session(
login.value().session.id());Memory auth
rix.auth.memory() creates an auth service backed by in-memory user and session stores.
auto auth = rix.auth.memory();This is useful for:
examples
tests
local development
small demos
temporary applicationsMemory auth does not persist users or sessions after the process exits.
For real applications that need durable users and sessions, use a database-backed store.
Register a user
Use:
auto registered = auth.register_user({
"ada@example.com",
"correct-password"});The first field is the email.
The second field is the plain-text password.
The password is hashed before storage.
The plain-text password should not be logged.
Check registration errors
register_user returns a result.
Check the result before using the user:
if (registered.failed())
{
const auto &error = registered.error();
rix.debug.eprint(
"auth error:",
rix.auth.error.to_string(error),
error.message());
return 1;
}Then access the created user:
const auto &user = registered.value();Read the registered user
rix.debug.print("id:", registered.value().id());
rix.debug.print("email:", registered.value().email());A user has:
id
email
password hash
email verification state
active state
timestampsDo not print the password hash in application output.
Log in
Use:
auto login = auth.login({
"ada@example.com",
"correct-password"});On success, login returns:
user
session
tokenAccess them with:
login.value().user
login.value().session
login.value().tokenCheck login errors
if (login.failed())
{
const auto &error = login.error();
rix.debug.eprint(
"auth error:",
rix.auth.error.to_string(error),
error.message());
return 1;
}A login can fail when the user does not exist, the password is wrong, the user is disabled, or email verification is required by the configuration.
Read login result
rix.debug.print("user:", login.value().user.email());
rix.debug.print("session:", login.value().session.id());
rix.debug.print("token issuer:", login.value().token.issuer());The session id and token value are sensitive.
In production, do not log raw session ids or token values.
The example prints the session id only to make the flow visible.
Authenticate a session
Use:
auto session = auth.authenticate_session(
login.value().session.id());If the session exists, is not revoked, and is not expired, the result succeeds.
if (session.ok())
{
rix.debug.print("session user id:", session.value().user_id());
}Check session errors
if (session.failed())
{
const auto &error = session.error();
rix.debug.eprint(
"auth error:",
rix.auth.error.to_string(error),
error.message());
return 1;
}A session can fail authentication when it is missing, expired, revoked, or invalid.
Complete flow
The normal memory auth flow is:
create auth service
register user
login user
authenticate session
handle errors explicitlyIn code:
auto auth = rix.auth.memory();
auto registered = auth.register_user({
"ada@example.com",
"correct-password"});
auto login = auth.login({
"ada@example.com",
"correct-password"});
auto session = auth.authenticate_session(
login.value().session.id());In real code, check each result before using value().
Error handling pattern
Use this pattern for auth operations:
auto result = auth.login({
"ada@example.com",
"correct-password"});
if (result.failed())
{
const auto &error = result.error();
rix.debug.eprint(
"auth error:",
rix.auth.error.to_string(error),
error.message());
return 1;
}Then use:
result.value()Only after checking success.
Duplicate registration example
This example shows a failed registration when the same email is used twice.
#include <rix.hpp>
int main()
{
auto auth = rix.auth.memory();
auto first = auth.register_user({
"ada@example.com",
"correct-password"});
if (first.failed())
{
return 1;
}
auto second = auth.register_user({
"ada@example.com",
"correct-password"});
if (second.failed())
{
rix.debug.eprint(
"expected auth error:",
rix.auth.error.to_string(second.error()),
second.error().message());
return 0;
}
return 1;
}Run:
vix run memory_register_login.cppThe second registration should fail because the user already exists.
Wrong password example
#include <rix.hpp>
int main()
{
auto auth = rix.auth.memory();
auto registered = auth.register_user({
"ada@example.com",
"correct-password"});
if (registered.failed())
{
return 1;
}
auto login = auth.login({
"ada@example.com",
"wrong-password"});
if (login.failed())
{
rix.debug.eprint(
"expected auth error:",
rix.auth.error.to_string(login.error()),
login.error().message());
return 0;
}
return 1;
}This should fail with an invalid credentials error.
Use a custom memory configuration
You can pass an auth configuration to memory.
auto config = rix.auth.config.development();
config.set_min_password_length(8);
config.set_token_ttl_seconds(60 * 15);
config.set_session_ttl_seconds(60 * 60 * 24 * 7);
auto auth = rix.auth.memory(config);Use this when the default behavior needs to be changed for an example or application.
Production-like memory config
For stricter rules:
auto config = rix.auth.config.production();
auto auth = rix.auth.memory(config);Production configuration requires email verification before login.
For this example, development configuration is simpler because it allows login immediately after registration.
Use in a Vix project
Create a project:
vix new rix-auth-memory --app
cd rix-auth-memoryAdd Rix:
vix add rix/rix
vix installMake sure vix.app contains:
deps = [
"rix/rix",
]A minimal vix.app can look like this:
name = "rix-auth-memory"
type = "executable"
standard = "c++20"
output_dir = "bin"
sources = [
"src/main.cpp",
]
include_dirs = [
"include",
"src",
]
deps = [
"rix/rix",
]
packages = [
"vix",
]
links = [
"vix::vix",
]Put the example code in:
src/main.cppBuild and run:
vix build
vix runSingle-file usage
For examples, tests, and quick experiments:
vix run memory_register_login.cppIf needed:
vix install -g rix/rix
vix run memory_register_login.cppFor project usage, prefer:
vix add rix/rix
vix installand keep the dependency in vix.app:
deps = [
"rix/rix",
]Use only auth with the facade
If you want the rix.* facade style but only want auth mounted, define the feature macro before including rix.hpp:
#define RIX_ENABLE_AUTH
#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;
}When at least one RIX_ENABLE_* macro is defined, only selected modules are mounted.
If you also want debug output:
#define RIX_ENABLE_AUTH
#define RIX_ENABLE_DEBUG
#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;
}
rix.debug.print("registered:", registered.value().email());
return 0;
}Use the independent package
For independent usage, install:
vix add rix/auth
vix installIn vix.app:
deps = [
"rix/auth",
]Then include auth package headers directly.
The examples in this documentation prefer the public facade:
#include <rix.hpp>and:
rix.authCommon mistakes
Forgetting to install Rix
If rix.hpp is not found, install Rix first.
For a project:
vix add rix/rix
vix installFor single-file usage:
vix install -g rix/rixPutting Rix in packages
Wrong:
packages = [
"rix/rix",
]Correct:
deps = [
"rix/rix",
]deps is for Vix Registry packages.
packages is for CMake package discovery.
Calling value() before checking success
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());Using production config without verifying email
This can fail:
auto auth = rix.auth.memory(
rix.auth.config.production());
auto registered = auth.register_user({
"ada@example.com",
"correct-password"});
auto login = auth.login({
"ada@example.com",
"correct-password"});Production config requires email verification before login.
For the simple memory example, use:
auto auth = rix.auth.memory();Printing sensitive values in production
Avoid printing:
plain-text passwords
password hashes
raw tokens
session idsThe example prints the session id only to make the flow understandable.
In production, avoid logging it.
Expecting memory auth to persist data
Memory auth is not durable.
When the process exits, users and sessions are gone.
Use database-backed stores for real applications.
What you should remember
Create a memory auth service:
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 a session:
auto session = auth.authenticate_session(
login.value().session.id());Check errors before using values:
if (login.failed())
{
rix.debug.eprint(
"auth error:",
rix.auth.error.to_string(login.error()),
login.error().message());
return 1;
}For project usage:
vix add rix/rix
vix installand keep:
deps = [
"rix/rix",
]Next step
Continue with password hashing.
Next: Password hashing