Skip to content

Authentication (JWT)

The framework supports JWT-based authentication with signing and optional encryption.


JWT Configuration

Configure signing and encryption keys in the configuration object. Generate keys using the keys_generator CLI tool.

cpp
using namespace framework;

configuration config;
config.jwt_.keys_.signature_.store(
    std::make_shared<const std::string>("base64:UtwkdboUSM8rGQREA4TmO+rTOeSlJJKrO2NKUSAjz6Q="));
config.jwt_.keys_.encryption_.store(
    std::make_shared<const std::string>("base64:8wDSwRRPsExIQyX1U97jh9A9Ed8jxuEe/K7J8eu5jWY="));
Config FieldPurpose
jwt_.keys_.signature_Key used to sign and verify JWT integrity.
jwt_.keys_.encryption_Key used to encrypt and decrypt the JWT payload.

auth::to_string(claims, sign_key, enc_key, duration) — Generating a Token

Creates a signed (and optionally encrypted) JWT string from a claims object.

cpp
#include <framework/support/auth.hpp>

using namespace framework;
using namespace framework::support::auth;

claims claims;
claims.subject_ = "user123";
claims.expiration_ = std::time(nullptr) + 3600; // 1 hour from now
claims.grants_["channels"] = {"read", "write"};
claims.grants_["admin"] = {"all"};

auto token = to_string(
    claims,
    config.jwt_.keys_.signature_.load(),
    config.jwt_.keys_.encryption_.load(),
    3600
);
ParamDescription
payloadA claims struct or boost::json::object with the token data.
signature_keyBase64-encoded signing key.
encryption_keyBase64-encoded encryption key.
durationToken lifetime in seconds (default: 86400).

Overload with JSON object

cpp
auto payload = boost::json::object{
    {"sub", "user123"},
    {"exp", std::time(nullptr) + 3600},
    {"grants", {{"channels", {"read", "write"}}}}
};

auto token = to_string(payload, sign_key, enc_key, 3600);

auth::from_string(token, sign_key, enc_key) — Verifying a Token

Decodes, decrypts, and verifies a JWT. Returns a result struct.

cpp
auto result = from_string(
    token,
    config.jwt_.keys_.signature_.load(),
    config.jwt_.keys_.encryption_.load()
);

if (result.is_valid()) {
    auto& claims = result.get_claims();
    fmt::println("Authenticated user: {}", claims.subject_);
}

The result struct

cpp
struct result {
    bool valid_;                        // True if token is valid
    value payload_;                     // Raw JSON payload
    std::optional<claims> claims_data_; // Parsed claims (if valid)
};
MethodDescription
is_valid()Returns true if the token was successfully verified.
get_claims()Returns the parsed claims struct.

The claims Struct

cpp
struct claims {
    std::string subject_;                                              // User ID ("sub")
    long expiration_;                                                  // Expiration timestamp ("exp")
    std::map<std::string, std::vector<std::string>, std::less<>> grants_;  // Permissions
};

Example grants:

json
{
  "sub": "user123",
  "exp": 1715000000,
  "grants": {
    "channels": ["read", "write"],
    "admin": ["all"],
    "cache:user:42:*": ["read"]
  }
}

jwt::has_grant(resource, permission) — Grant Checking

cpp
framework::support::auth::jwt jwt;
jwt.set_token(token);

if (jwt.has_grant("channels:private-chat-42", "read")) {
    // Authorized to read private-chat-42
}

Route Protection

Mark routes as requiring authentication:

cpp
using namespace framework;
using namespace framework::clients::http;

app.register_endpoint(
    http_verb_t::get,
    "/admin/stats",
    handler,
    nullptr,                // no validator
    gates::is_admin_all,    // gate (runs after JWT verification)
    true                    // requires JWT authentication
);

When requires_auth is true, the framework extracts the JWT from the Authorization header and verifies it before the handler runs.

Client-side: Send the token in the HTTP header:

Authorization: Bearer <token>