Sessions
This page explains how sessions work in rix/auth.
The examples use the public Rix facade:
#include <rix.hpp>and the Auth API through:
rix.authA session represents server-side login state.
When a user logs in, Rix Auth creates a session. The application can later authenticate that session id to know which user is connected.
Session flow
The normal session flow is:
login
-> create session
-> return session id
authenticate_session
-> find session
-> reject invalid session
-> reject expired session
-> reject revoked session
refresh_session
-> extend session lifetime
-> update last seen time
logout
-> revoke sessionComplete example
Create a file:
mkdir -p ~/rix-auth-sessions
cd ~/rix-auth-sessions
touch sessions.cppAdd:
#include <rix.hpp>
int main()
{
rix.debug.print("== rix/auth sessions ==");
auto auth = rix.auth.memory();
auto registered = auth.register_user({"grace@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;
}
auto login = auth.login({"grace@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;
}
const auto session_id = login.value().session.id();
rix.debug.print("created session:", session_id);
rix.debug.print("user id:", login.value().session.user_id());
rix.debug.print("created at:", login.value().session.created_at());
rix.debug.print("expires at:", login.value().session.expires_at());
auto session = auth.authenticate_session(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());
auto refreshed = auth.refresh_session(session_id);
if (refreshed.failed())
{
const auto &error = refreshed.error();
rix.debug.eprint(
"auth error:",
rix.auth.error.to_string(error),
error.message()
);
return 1;
}
rix.debug.print("----------------------------------------");
rix.debug.print("OK:", "session refreshed");
rix.debug.print("new expires at:", refreshed.value().expires_at());
rix.debug.print("last seen at:", refreshed.value().last_seen_at());
auto logout = auth.logout(session_id);
if (logout.failed())
{
const auto &error = logout.error();
rix.debug.eprint(
"auth error:",
rix.auth.error.to_string(error),
error.message()
);
return 1;
}
rix.debug.print("----------------------------------------");
rix.debug.print("OK:", "logout successful");
auto after_logout = auth.authenticate_session(session_id);
if (after_logout.ok())
{
rix.debug.eprint("ERROR:", "session should not authenticate after logout");
return 1;
}
rix.debug.print("session rejected after logout");
return 0;
}Run it:
vix run sessions.cppIf Rix is not available yet for single-file usage:
vix install -g rix/rix
vix run sessions.cppExpected output
The output should look like this:
== rix/auth sessions ==
created session: session_...
user id: user_...
created at: ...
expires at: ...
----------------------------------------
OK: session authenticated
session user id: user_...
----------------------------------------
OK: session refreshed
new expires at: ...
last seen at: ...
----------------------------------------
OK: logout successful
session rejected after logoutThe exact ids and timestamps will be different.
Create a session
A session is created during login:
auto login = auth.login({"grace@example.com", "correct-password"});A successful login returns:
login.value().sessionThe session contains:
login.value().session.id()
login.value().session.user_id()
login.value().session.created_at()
login.value().session.expires_at()
login.value().session.last_seen_at()
login.value().session.revoked()The session id is sensitive.
Do not log session ids in production.
Authenticate a session
Use:
auto session = auth.authenticate_session(session_id);A successful result means the session can be used.
A usable session must be:
valid
not revoked
not expiredAlways check the result:
if (session.failed())
{
const auto &error = session.error();
return 1;
}Then use the authenticated user id:
auto user_id = session.value().user_id();In an HTTP application, this user id is usually attached to the request context or used to load the authenticated user.
Refresh a session
Use:
auto refreshed = auth.refresh_session(session_id);Refreshing a session updates:
refreshed.value().expires_at()
refreshed.value().last_seen_at()A session can only be refreshed if it is still usable.
That means an expired or revoked session should not be refreshed.
Logout
Use:
auto status = auth.logout(session_id);Logout revokes the session.
A revoked session remains stored, but it can no longer be used.
Always check the status:
if (status.failed())
{
const auto &error = status.error();
return 1;
}After logout, authentication should fail:
auto after_logout = auth.authenticate_session(session_id);
if (after_logout.ok())
{
return 1;
}Logout all sessions for a user
Use:
auto status = auth.logout_user(user_id);This revokes every session attached to that user.
Use it when:
the user changes password
the user clicks "logout from all devices"
an account is disabled
a security event requires immediate disconnectExample:
auto status = auth.logout_user(login.value().user.id());
if (status.failed())
{
const auto &error = status.error();
return 1;
}Session lifetime
Session lifetime is controlled by Auth configuration.
Development configuration:
auto config = rix.auth.config.development();Production configuration:
auto config = rix.auth.config.production();Set the session lifetime in seconds:
auto config = rix.auth.config.development();
config.set_session_ttl_seconds(60 * 60 * 24 * 7);
auto auth = rix.auth.memory(config);This example sets a seven-day session lifetime.
Short session example
For tests, you can use a short lifetime:
auto config = rix.auth.config.development();
config.set_session_ttl_seconds(60);
auto auth = rix.auth.memory(config);This creates sessions that expire after one minute.
Use short lifetimes for tests and examples.
Use production settings for real deployments.
Session fields
A session stores:
id
user_id
created_at
expires_at
last_seen_at
revokedid is the session identifier.
user_id is the authenticated user.
created_at is the creation timestamp.
expires_at is the expiration timestamp.
last_seen_at is updated when the session is refreshed.
revoked tells whether the session has been manually invalidated.
Session model helpers
The session model exposes helper methods:
session.valid()
session.has_id()
session.has_user_id()
session.has_id(session_id)
session.belongs_to(user_id)
session.expired(now)
session.usable(now)
session.refreshable(now)
session.revoked()These are useful in store implementations, tests, and advanced integrations.
Most application code should use:
auth.authenticate_session(session_id)instead of manually checking the session state.
Memory sessions
The examples use:
auto auth = rix.auth.memory();Memory auth stores sessions in memory.
That means:
sessions are lost when the process exits
sessions do not survive restart
sessions are useful for examples and testsUse memory sessions for learning, tests, and temporary tools.
Use database sessions for real applications.
Database sessions
For durable sessions:
auto config = rix.auth.config.production();
auto auth = rix.auth.database(db, config);Database auth stores sessions through a database-backed session store.
Use database auth when users and sessions must survive process restarts.
Session store helpers
The facade exposes store helpers:
auto sessions = rix.auth.stores.memory_sessions();For database sessions:
auto sessions = rix.auth.stores.database_sessions(db);Most applications do not need to create session stores directly.
Use:
auto auth = rix.auth.memory();or:
auto auth = rix.auth.database(db);Common session errors
Session operations can fail with errors such as:
InvalidSession
SessionExpired
SessionRevoked
StoreError
InvalidInputUse stable error codes for programmatic decisions:
if (rix.auth.error.is(
session.error(),
rixlib::auth::AuthErrorCode::SessionExpired))
{
// ask the user to login again
}Use the error message for diagnostics:
session.error().message()Security notes
Do not log session ids in production.
Do not send session ids to places that should not receive authentication secrets.
Use HTTPS in real applications.
Use database-backed sessions when session state must survive restarts.
Use logout to revoke sessions instead of deleting users.
Use logout_user when all sessions for a user must be invalidated.
What you should remember
Login creates a session:
auto login = auth.login({
"grace@example.com",
"correct-password"});Authenticate the session:
auto session = auth.authenticate_session(login.value().session.id());Refresh the session:
auto refreshed = auth.refresh_session(login.value().session.id());Logout revokes the session:
auto status = auth.logout(login.value().session.id());Logout all sessions for a user:
auto status = auth.logout_user(user_id);Always check results and statuses before using returned values.
Next step
Learn how tokens work.
Next: Tokens