Rix is the official package layer for Vix.cpp Browse packages
Skip to content

Token Issue

This example shows how to issue a token for a registered user with rix/auth.

The example uses the public Rix facade:

cpp
#include <rix.hpp>

and accesses auth through:

cpp
rix.auth

It uses an in-memory auth service, so it is useful for examples, tests, and local development.

Create the file

bash
mkdir -p ~/rix-auth-token-example
cd ~/rix-auth-token-example
touch token_issue.cpp

Add:

cpp
#include <rix.hpp>

int main()
{
  rix.debug.print("== rix/auth token issue ==");

  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:

bash
vix run token_issue.cpp

If Rix is not available yet for single-file usage:

bash
vix install -g rix/rix
vix run token_issue.cpp

Expected output shape:

txt
== rix/auth token issue ==
OK: token issued
user id: user_...
issuer: rix/auth
issued at: ...
expires at: ...

What this example does

The example creates an in-memory auth service:

cpp
auto auth = rix.auth.memory();

It registers a user:

cpp
auto registered = auth.register_user({
    "linus@example.com",
    "correct-password"});

It issues a token for the registered user:

cpp
auto token = auth.issue_token(
    registered.value().id());

Then it prints token metadata:

cpp
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());

Issue a token

Use:

cpp
auto token = auth.issue_token(user_id);

The user_id must identify a valid user.

A token result contains a token value on success.

Check the result before using it:

cpp
if (token.failed())
{
  const auto &error = token.error();

  rix.debug.eprint(
      "auth error:",
      rix.auth.error.to_string(error),
      error.message());

  return 1;
}

Then access:

cpp
token.value()

Token fields

A token contains:

txt
value
user id
issuer
issued timestamp
expiration timestamp
revocation state

In examples, it is safe to print metadata such as issuer and timestamps.

Avoid printing the raw token value in production logs.

Token value is sensitive

The raw token value is sensitive.

Avoid logging:

cpp
token.value().value()

In production, do not print raw token values, passwords, password hashes, or session ids.

This example prints only:

txt
user id
issuer
issued at
expires at

Token issuer

The issuer identifies the auth system that created the token.

By default:

txt
rix/auth

Read it with:

cpp
token.value().issuer()

You can configure the issuer through auth config:

cpp
auto config = rix.auth.config.development();

config.set_issuer("my-app");

auto auth = rix.auth.memory(config);

Token expiration

Tokens are short-lived.

Read the expiration timestamp with:

cpp
token.value().expires_at()

Read the issue timestamp with:

cpp
token.value().issued_at()

The timestamps are Unix timestamps in seconds.

Token lifetime

Token lifetime is controlled by auth configuration:

cpp
auto config = rix.auth.config.development();

config.set_token_ttl_seconds(60 * 15);

auto auth = rix.auth.memory(config);

This creates tokens that last 15 minutes.

Session lifetime is separate:

cpp
config.set_session_ttl_seconds(60 * 60 * 24 * 7);

The token can be short-lived while the server-side session lasts longer.

Complete custom token lifetime example

cpp
#include <rix.hpp>

int main()
{
  auto config = rix.auth.config.development();

  config.set_token_ttl_seconds(60 * 5);
  config.set_issuer("rix/auth/example");

  auto auth = rix.auth.memory(config);

  auto registered = auth.register_user({
      "linus@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 token = auth.issue_token(
      registered.value().id());

  if (token.failed())
  {
    rix.debug.eprint(
        "auth error:",
        rix.auth.error.to_string(token.error()),
        token.error().message());

    return 1;
  }

  rix.debug.print("issuer:", token.value().issuer());
  rix.debug.print("expires at:", token.value().expires_at());

  return 0;
}

Run:

bash
vix run token_issue.cpp

Issue a token after login

A successful login already returns a token:

cpp
auto login = auth.login({
    "linus@example.com",
    "correct-password"});

Access it with:

cpp
login.value().token

Example:

cpp
auto login = auth.login({
    "linus@example.com",
    "correct-password"});

if (login.failed())
{
  return 1;
}

rix.debug.print(
    "login token issuer:",
    login.value().token.issuer());

Use issue_token when you need to issue a new token for an already known user id.

Issue token for missing user

Issuing a token for a missing user should fail:

cpp
#include <rix.hpp>

int main()
{
  auto auth = rix.auth.memory();

  auto token = auth.issue_token("missing-user");

  if (token.failed())
  {
    rix.debug.eprint(
        "expected auth error:",
        rix.auth.error.to_string(token.error()),
        token.error().message());

    return 0;
  }

  return 1;
}

Run:

bash
vix run token_issue.cpp

The failure is expected because the user does not exist.

Check token usability

A token object can be checked at a given time:

cpp
const auto now = token.value().issued_at();

if (token.value().usable(now))
{
  rix.debug.print("token is usable");
}

A usable token must be:

txt
valid
not revoked
not expired

Check token ownership

Use:

cpp
token.value().belongs_to(user_id)

Example:

cpp
if (token.value().belongs_to(registered.value().id()))
{
  rix.debug.print("token belongs to user");
}

Check token issuer

Use:

cpp
token.value().issued_by("rix/auth")

Example:

cpp
if (token.value().issued_by("rix/auth"))
{
  rix.debug.print("token issuer accepted");
}

Revoke a token object

A token object can be revoked in memory:

cpp
auto value = token.value();

value.revoke();

if (!value.usable(value.issued_at()))
{
  rix.debug.print("token revoked");
}

This changes the token object.

It does not revoke every copy of that token in an external token store.

For durable token revocation in a real application, use an application-level store or token tracking strategy.

Error handling pattern

Use this pattern for token operations:

cpp
auto result = auth.issue_token(user_id);

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:

cpp
result.value()

Only after checking success.

Use in a Vix project

Create a project:

bash
vix new rix-auth-token --app
cd rix-auth-token

Add Rix:

bash
vix add rix/rix
vix install

Make sure vix.app contains:

txt
deps = [
  "rix/rix",
]

A minimal vix.app can look like this:

txt
name = "rix-auth-token"
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:

txt
src/main.cpp

Build and run:

bash
vix build
vix run

Single-file usage

For examples, tests, and quick experiments:

bash
vix run token_issue.cpp

If needed:

bash
vix install -g rix/rix
vix run token_issue.cpp

For project usage, prefer:

bash
vix add rix/rix
vix install

and keep the dependency in vix.app:

txt
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:

cpp
#define RIX_ENABLE_AUTH
#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());

  return token.ok() ? 0 : 1;
}

When at least one RIX_ENABLE_* macro is defined, only selected modules are mounted.

If you also want debug output:

cpp
#define RIX_ENABLE_AUTH
#define RIX_ENABLE_DEBUG
#include <rix.hpp>

int main()
{
  auto auth = rix.auth.memory();

  auto registered = auth.register_user({
      "linus@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 token = auth.issue_token(
      registered.value().id());

  if (token.failed())
  {
    rix.debug.eprint(
        "auth error:",
        rix.auth.error.to_string(token.error()),
        token.error().message());

    return 1;
  }

  rix.debug.print("token issued");
  return 0;
}

Use the independent package

For independent usage, install:

bash
vix add rix/auth
vix install

In vix.app:

txt
deps = [
  "rix/auth",
]

Then include auth package headers directly.

The examples in this documentation prefer the public facade:

cpp
#include <rix.hpp>

and:

cpp
rix.auth

Common mistakes

Forgetting to install Rix

If rix.hpp is not found, install Rix first.

For a project:

bash
vix add rix/rix
vix install

For single-file usage:

bash
vix install -g rix/rix

Putting Rix in packages

Wrong:

txt
packages = [
  "rix/rix",
]

Correct:

txt
deps = [
  "rix/rix",
]

deps is for Vix Registry packages.

packages is for CMake package discovery.

Calling value() before checking success

Wrong:

cpp
auto token = auth.issue_token(user_id);

rix.debug.print(token.value().issuer());

Correct:

cpp
auto token = auth.issue_token(user_id);

if (token.failed())
{
  return 1;
}

rix.debug.print(token.value().issuer());

Printing raw token values

Avoid printing:

cpp
token.value().value()

The raw token value is sensitive.

Use metadata such as issuer and expiration in examples.

Expecting tokens and sessions to be the same thing

A session is server-side authentication state.

A token is a short-lived value issued for a user.

They have separate lifetimes:

cpp
config.set_session_ttl_seconds(...);
config.set_token_ttl_seconds(...);

Issuing a token for a missing user

This should fail:

cpp
auto token = auth.issue_token("missing-user");

Use a real user id from registration or login.

Expecting memory auth to persist data

Memory auth does not persist users or sessions after the process exits.

Use database-backed stores for real applications.

What you should remember

Create memory auth:

cpp
auto auth = rix.auth.memory();

Register a user:

cpp
auto registered = auth.register_user({
    "linus@example.com",
    "correct-password"});

Issue a token:

cpp
auto token = auth.issue_token(
    registered.value().id());

Check errors before using values:

cpp
if (token.failed())
{
  rix.debug.eprint(
      "auth error:",
      rix.auth.error.to_string(token.error()),
      token.error().message());

  return 1;
}

Avoid logging raw token values.

For project usage:

bash
vix add rix/rix
vix install

and keep:

txt
deps = [
  "rix/rix",
]

Next step

Continue with PDF examples.

Next: Basic PDF

Released under the MIT License.