Tokens
This page explains how tokens work in rix/auth.
The examples use the public Rix facade:
#include <rix.hpp>and the Auth API through:
rix.authA token is a short-lived authentication value attached to a user.
Tokens are created during login and can also be issued directly for a user.
Token flow
The normal token flow is:
login
-> authenticate user credentials
-> create session
-> issue token
issue_token
-> create a short-lived token for a user
token model
-> stores token value
-> stores user id
-> stores issuer
-> stores issued_at
-> stores expires_at
-> stores revoked stateRix Auth currently exposes token creation and token model helpers.
Session authentication is still done with server-side sessions.
Complete example
Create a file:
mkdir -p ~/rix-auth-tokens
cd ~/rix-auth-tokens
touch tokens.cppAdd:
#include <rix.hpp>
int main()
{
rix.debug.print("== rix/auth tokens ==");
auto auth = rix.auth.memory();
auto registered = auth.register_user({"linus@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 token = auth.issue_token(registered.value().id());
if (token.failed())
{
const auto &error = token.error();
rix.debug.eprint(
"auth error:",
rix.auth.error.to_string(error),
error.message()
);
return 1;
}
rix.debug.print("OK:", "token issued");
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());
return 0;
}Run it:
vix run tokens.cppIf Rix is not available yet for single-file usage:
vix install -g rix/rix
vix run tokens.cppExpected output
The output should look like this:
== rix/auth tokens ==
OK: token issued
user id: user_...
issuer: rix/auth
issued at: ...
expires at: ...The exact user id and timestamps will be different.
The raw token value is intentionally not printed in this example.
Token from login
A successful login returns a token together with the user and session:
auto login = auth.login({"ada@example.com", "correct-password"});After checking the result:
if (login.failed())
{
const auto &error = login.error();
return 1;
}You can access:
login.value().tokenThe login result contains:
login.value().user
login.value().session
login.value().tokenThe user contains the authenticated identity.
The session represents server-side login state.
The token is a short-lived value attached to the user.
Issue a token directly
Use:
auto token = auth.issue_token(user_id);Example:
auto token = auth.issue_token(registered.value().id());
if (token.failed())
{
const auto &error = token.error();
rix.debug.eprint(
"auth error:",
rix.auth.error.to_string(error),
error.message()
);
return 1;
}A successful result contains a Token.
Token fields
A token stores:
value
user_id
issuer
issued_at
expires_at
revokedRead token fields:
token.value().value()
token.value().user_id()
token.value().issuer()
token.value().issued_at()
token.value().expires_at()
token.value().revoked()The token value is sensitive.
Do not log raw token values in production.
Token issuer
The issuer comes from Auth configuration:
auto config = rix.auth.config.development();
config.set_issuer("my-app");
auto auth = rix.auth.memory(config);Tokens issued by this auth service will use:
token.value().issuer()to expose the configured issuer.
The default issuer is:
rix/authToken lifetime
Token lifetime is controlled by Auth configuration.
Set token lifetime in seconds:
auto config = rix.auth.config.development();
config.set_token_ttl_seconds(60 * 15);
auto auth = rix.auth.memory(config);This example sets a fifteen-minute token lifetime.
Production configuration uses a short token lifetime by default.
Short token example
For tests, you can use a very short lifetime:
auto config = rix.auth.config.development();
config.set_token_ttl_seconds(60);
auto auth = rix.auth.memory(config);This creates tokens that expire after one minute.
Short lifetimes are useful for tests and examples.
Use production settings for real deployments.
Token model helpers
The token model exposes helper methods:
token.valid()
token.has_value()
token.has_user_id()
token.belongs_to(user_id)
token.matches(raw_value)
token.issued_by(issuer)
token.expired(now)
token.usable(now)
token.revoked()Example:
const auto &value = token.value();
if (value.issued_by("rix/auth"))
{
rix.debug.print("issuer is valid");
}Another example:
if (value.belongs_to(registered.value().id()))
{
rix.debug.print("token belongs to user");
}Token expiration
A token is expired when the current time is greater than or equal to its expiration timestamp.
The model helper is:
token.expired(now)A token is usable when it is:
valid
not revoked
not expiredThe model helper is:
token.usable(now)Most application code should avoid manually trusting token values without a higher-level validation flow.
Use the token helpers when writing tests, integrations, or future token validation code.
Token revocation
The token model supports revocation:
auto value = token.value();
value.revoke();After revocation:
value.revoked()returns true.
A revoked token is not usable:
value.usable(now)returns false.
Error handling
Token issuing returns an explicit result:
auto token = auth.issue_token(user_id);
if (token.failed())
{
const auto &error = token.error();
}Use the facade error helper:
rix.auth.error.to_string(error)Use the error message for diagnostics:
error.message()Example:
if (token.failed())
{
const auto &error = token.error();
rix.debug.eprint(
"auth error:",
rix.auth.error.to_string(error),
error.message()
);
return 1;
}Common token errors
Token operations can fail with errors such as:
InvalidInput
InvalidToken
TokenExpired
TokenRevoked
StoreError
CryptoError
UnknownUse stable error codes for programmatic decisions.
Use messages for diagnostics.
Token security
Treat token values as secrets.
Avoid logging:
raw token values
session ids
password hashes
plain-text passwordsDo not expose token values in debug output.
Do not store raw token values in places that should not contain authentication secrets.
Use short token lifetimes for real applications.
Use HTTPS in real deployments.
Tokens and sessions
Login returns both a session and a token:
login.value().session
login.value().tokenThe session is server-side state.
The token is a short-lived value attached to the authenticated user.
Use sessions when the application needs server-side revocation and persistent login state.
Use tokens when the application needs a short-lived authentication value.
Complete login token 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", "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 &token = login.value().token;
rix.debug.print("token issued");
rix.debug.print("user id:", token.user_id());
rix.debug.print("issuer:", token.issuer());
rix.debug.print("expires at:", token.expires_at());
return 0;
}Run it:
vix run tokens.cppWhat you should remember
Login returns a token:
login.value().tokenYou can issue a token directly:
auto token = auth.issue_token(user_id);A token contains:
token.value().user_id()
token.value().issuer()
token.value().issued_at()
token.value().expires_at()The raw token value is sensitive:
token.value().value()Do not log it in production.
Token lifetime is configured with:
config.set_token_ttl_seconds(...)Token issuer is configured with:
config.set_issuer(...)Always check results before using .value().
Next step
Learn how to configure Auth.
Next: Configuration