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

Session Refresh and Logout ​

This example shows how to refresh a session and log out 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-session-example
cd ~/rix-auth-session-example
touch session_refresh_logout.cpp

Add:

cpp
#include <rix.hpp>

int main()
{
  rix.debug.print("== rix/auth session refresh and logout ==");

  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("expires at:", login.value().session.expires_at());

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

  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 be valid after logout");
    return 1;
  }

  rix.debug.print("session rejected after logout");

  return 0;
}

Run it:

bash
vix run session_refresh_logout.cpp

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

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

Expected output shape:

txt
== rix/auth session refresh and logout ==
created session: session_...
expires at: ...
----------------------------------------
OK: session refreshed
new expires at: ...
----------------------------------------
OK: logout successful
session rejected after logout

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({
    "grace@example.com",
    "correct-password"});

It logs the user in:

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

It stores the session id:

cpp
const auto session_id = login.value().session.id();

It refreshes the session:

cpp
auto refreshed = auth.refresh_session(session_id);

It logs out:

cpp
auto logout = auth.logout(session_id);

Then it checks that the session is rejected after logout:

cpp
auto after_logout = auth.authenticate_session(session_id);

Create a session ​

A session is created when login succeeds.

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

The login result contains:

txt
user
session
token

Access the session with:

cpp
login.value().session

Use the session id for later session operations:

cpp
const auto session_id = login.value().session.id();

Refresh a session ​

Use:

cpp
auto refreshed = auth.refresh_session(session_id);

If the session is valid, not expired, and not revoked, refresh succeeds.

The refreshed session has an updated expiration timestamp.

cpp
rix.debug.print(
    "new expires at:",
    refreshed.value().expires_at());

Check refresh errors ​

refresh_session returns a result.

Check it before using the refreshed session:

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

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

  return 1;
}

Then use:

cpp
refreshed.value()

Logout ​

Use:

cpp
auto logout = auth.logout(session_id);

Logout revokes the session.

A revoked session remains stored, but it can no longer be used for authentication.

Check logout errors ​

logout returns a status.

Use:

cpp
logout.ok()
logout.failed()
logout.error()

Example:

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

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

  return 1;
}

Authenticate after logout ​

After logout, this should fail:

cpp
auto after_logout = auth.authenticate_session(session_id);

Check it:

cpp
if (after_logout.ok())
{
  rix.debug.eprint("ERROR:", "session should not be valid after logout");
  return 1;
}

This confirms that logout revoked the session.

Normal session flow ​

The normal flow is:

txt
register user
login user
get session id
refresh session when needed
logout when done
reject session after logout

In code:

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

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

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

const auto session_id = login.value().session.id();

auto refreshed = auth.refresh_session(session_id);

auto logout = auth.logout(session_id);

In real code, check every result before calling value().

Error handling pattern ​

Use this pattern for session operations that return a value:

cpp
auto result = auth.refresh_session(session_id);

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

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

  return 1;
}

Use this pattern for operations that only return a status:

cpp
auto status = auth.logout(session_id);

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

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

  return 1;
}

Refresh before logout ​

This is valid:

cpp
auto refreshed = auth.refresh_session(session_id);

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

auto logout = auth.logout(session_id);

Refresh keeps the session alive.

Logout revokes it.

After logout, refresh should fail because the session is no longer usable.

Refresh after logout example ​

cpp
#include <rix.hpp>

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

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

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

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

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

  const auto session_id = login.value().session.id();

  auto logout = auth.logout(session_id);

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

  auto refreshed = auth.refresh_session(session_id);

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

    return 0;
  }

  return 1;
}

Run:

bash
vix run session_refresh_logout.cpp

The refresh after logout should fail.

Logout all sessions for a user ​

Use:

cpp
auto status = auth.logout_user(user_id);

Example:

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

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

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

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

if (login1.failed() || login2.failed())
{
  return 1;
}

auto status = auth.logout_user(registered.value().id());

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

  return 1;
}

logout_user revokes all sessions belonging to the given user.

Authenticate session directly ​

Use:

cpp
auto session = auth.authenticate_session(session_id);

This checks that the session:

txt
exists
is valid
is not expired
is not revoked

Example:

cpp
if (session.ok())
{
  rix.debug.print("session user id:", session.value().user_id());
}

Custom session lifetime ​

You can configure session lifetime with auth config:

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

config.set_session_ttl_seconds(60 * 60);

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

This creates sessions that last one hour.

Use this when testing session expiration behavior or changing application policy.

Token lifetime is separate ​

Session lifetime and token lifetime are separate settings.

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

The session controls server-side authentication.

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

Safe output ​

Session ids are sensitive.

This example prints the session id so the flow is easy to see.

For production logs, avoid printing:

txt
session ids
raw token values
passwords
password hashes

Use stable user ids, event ids, or redacted values instead.

Use in a Vix project ​

Create a project:

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

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-session"
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 session_refresh_logout.cpp

If needed:

bash
vix install -g rix/rix
vix run session_refresh_logout.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({
      "grace@example.com",
      "correct-password"});

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

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

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

  auto logout = auth.logout(login.value().session.id());

  return logout.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({
      "grace@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:

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 refreshed = auth.refresh_session(session_id);

rix.debug.print(refreshed.value().expires_at());

Correct:

cpp
auto refreshed = auth.refresh_session(session_id);

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

rix.debug.print(refreshed.value().expires_at());

Expecting logout to delete the session ​

Logout revokes the session.

A revoked session can remain stored, but it is not usable.

This makes logout behavior safer and easier to audit.

Refreshing a revoked session ​

This should fail:

cpp
auth.logout(session_id);

auto refreshed = auth.refresh_session(session_id);

A revoked session is not refreshable.

Printing session ids in production ​

Avoid logging raw session ids.

They are sensitive authentication values.

The example prints them only to make the flow visible.

Expecting memory sessions to persist ​

Memory sessions disappear when the process exits.

Use database-backed stores for durable auth.

What you should remember ​

Create memory auth:

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

Login creates a session:

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

Refresh the session:

cpp
auto refreshed = auth.refresh_session(
    login.value().session.id());

Logout revokes the session:

cpp
auto logout = auth.logout(
    login.value().session.id());

After logout, authentication should fail:

cpp
auto after_logout = auth.authenticate_session(
    login.value().session.id());

Check every result before using value().

For project usage:

bash
vix add rix/rix
vix install

and keep:

txt
deps = [
  "rix/rix",
]

Next step ​

Continue with token issue.

Next: Token issue

Released under the MIT License.