DeterministicESPAsyncWebServer
v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
jwt.h
Go to the documentation of this file.
1
// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2
// SPDX-License-Identifier: AGPL-3.0-or-later
3
4
/**
5
* @file jwt.h
6
* @brief Zero-heap JWT (JSON Web Token) bearer-auth verification, HS256.
7
*
8
* Stateless request authentication: a client presents `Authorization: Bearer
9
* <jwt>` and the server verifies the token's HMAC-SHA-256 signature against a
10
* shared secret (reusing the SSH crypto layer's HMAC). No sessions, no per-client
11
* state, no heap - all work happens in fixed stack/BSS buffers and the whole core
12
* is host-testable (env:native_jwt).
13
*
14
* Only HS256 (HMAC-SHA-256) is supported - the deterministic, allocation-free
15
* choice for a constrained device sharing a secret with its issuer. RS256/ES256
16
* (asymmetric) are out of scope. Signature verification is constant-time.
17
*
18
* The base verifier (jwt_verify_hs256 / jwt_bearer_valid) checks only the
19
* signature. The `*_at` variants additionally enforce the RFC 7519 time claims
20
* (`exp` §4.1.4 and `nbf` §4.1.5) against a caller-supplied wall-clock epoch, with a
21
* skew leeway - pass now=0 on a clockless device to skip the time checks (the
22
* signature still gates). `iat` (§4.1.6) is informational; read it with
23
* jwt_claim_int() if you want it.
24
*/
25
26
#ifndef DETERMINISTICESPASYNCWEBSERVER_JWT_H
27
#define DETERMINISTICESPASYNCWEBSERVER_JWT_H
28
29
#include "
ServerConfig.h
"
30
#include <stddef.h>
31
#include <stdint.h>
32
33
#if DETWS_ENABLE_JWT
34
35
/**
36
* @brief Verify the HS256 signature of a JWT.
37
*
38
* Checks that the token has exactly the `header.payload.signature` shape and that
39
* base64url(HMAC-SHA-256(secret, "header.payload")) equals the signature segment
40
* (constant-time). Does not inspect claims.
41
*
42
* @param token the compact JWT string.
43
* @param token_len length of @p token (e.g. strlen).
44
* @param secret HMAC key bytes.
45
* @param secret_len key length.
46
* @return true if the signature is valid.
47
*/
48
bool
jwt_verify_hs256(
const
char
*token,
size_t
token_len,
const
uint8_t *secret,
size_t
secret_len);
49
50
/**
51
* @brief Validate an `Authorization` header value carrying a Bearer JWT.
52
*
53
* Accepts a value beginning with `Bearer ` (case-insensitive scheme), then
54
* verifies the token via jwt_verify_hs256().
55
*
56
* @param auth_header the full Authorization header value (may be nullptr).
57
* @param secret HMAC key bytes.
58
* @param secret_len key length.
59
* @return true if a well-formed Bearer token validates.
60
*/
61
bool
jwt_bearer_valid(
const
char
*auth_header,
const
uint8_t *secret,
size_t
secret_len);
62
63
/**
64
* @brief Check a JWT's time-based validity (RFC 7519 `exp` / `nbf`) against a clock.
65
*
66
* Enforces `exp` (§4.1.4: rejected once @p now_epoch has passed it) and `nbf`
67
* (§4.1.5: rejected before it), each within @p leeway_s seconds of skew tolerance.
68
* An absent claim is not enforced. Does NOT check the signature - pair with
69
* jwt_verify_hs256(). The comparisons are written to avoid integer overflow near the
70
* `long` epoch range.
71
*
72
* @param now_epoch current Unix time in seconds; <= 0 means "no wall clock", so the
73
* time claims cannot be evaluated and the function returns true (the
74
* signature check remains the gate).
75
* @param leeway_s allowed clock skew in seconds (0 for none).
76
* @return true if the token is currently within its validity window (or no clock is set).
77
*/
78
bool
jwt_time_valid(
const
char
*token,
size_t
token_len,
long
now_epoch,
long
leeway_s);
79
80
/**
81
* @brief Verify a JWT's HS256 signature AND its `exp` / `nbf` time claims.
82
*
83
* jwt_verify_hs256() && jwt_time_valid(). On a clockless device (@p now_epoch <= 0)
84
* this reduces to the signature-only check.
85
*/
86
bool
jwt_verify_hs256_at(
const
char
*token,
size_t
token_len,
const
uint8_t *secret,
size_t
secret_len,
long
now_epoch,
87
long
leeway_s);
88
89
/**
90
* @brief Validate a Bearer `Authorization` header, enforcing `exp` / `nbf` when clocked.
91
*
92
* jwt_bearer_valid() plus the RFC 7519 time-claim check. Pass @p now_epoch from your
93
* time source (e.g. `(long)detws_time_now()`); 0 skips the time checks.
94
*/
95
bool
jwt_bearer_valid_at(
const
char
*auth_header,
const
uint8_t *secret,
size_t
secret_len,
long
now_epoch,
96
long
leeway_s);
97
98
/**
99
* @brief Read an integer claim (e.g. "exp", "iat", "nbf") from a JWT payload.
100
*
101
* base64url-decodes the payload segment and scans the JSON for a top-level
102
* numeric member @p name. Does not verify the signature - call
103
* jwt_verify_hs256() first.
104
*
105
* @param token the compact JWT string.
106
* @param token_len length of @p token.
107
* @param name claim name (without quotes).
108
* @param out receives the parsed value on success.
109
* @return true if the claim is present and parses as an integer.
110
*/
111
bool
jwt_claim_int(
const
char
*token,
size_t
token_len,
const
char
*name,
long
*out);
112
113
/**
114
* @brief Read a string claim (e.g. "sub", "role", "scope") from a JWT payload.
115
*
116
* base64url-decodes the payload and copies the top-level string member @p name
117
* into @p out (null-terminated, bounded by @p out_cap). Does not verify the
118
* signature - call jwt_verify_hs256() first. Minimal unescaping (handles `\"` and
119
* `\\`; other escapes are copied without their backslash), which suits
120
* scope / role / sub values.
121
*
122
* @return true if the claim is present and is a string that fit in @p out.
123
*/
124
bool
jwt_claim_str(
const
char
*token,
size_t
token_len,
const
char
*name,
char
*out,
size_t
out_cap);
125
126
/**
127
* @brief Test whether a space-separated OAuth2 scope claim grants @p required.
128
*
129
* @param scope_claim the `scope` claim value (space-delimited scopes, RFC 6749 3.3).
130
* @param required the scope to look for.
131
* @return true if @p required is one of the whole space-separated tokens.
132
*/
133
bool
jwt_scope_allows(
const
char
*scope_claim,
const
char
*required);
134
135
#endif
// DETWS_ENABLE_JWT
136
137
#endif
// DETERMINISTICESPASYNCWEBSERVER_JWT_H
ServerConfig.h
User-facing configuration for DeterministicESPAsyncWebServer.
src
services
jwt
jwt.h
Generated by
1.9.8