challenger

OAuth 2.0-based authentication service that validates user can receive messages at a certain address
Log | Files | Refs | Submodules | README | LICENSE

commit f7ddc037b7a5d983f772c029a96f261055c9a8ed
parent 1418e47826457b8bf11c8d5464bce0126a06e6eb
Author: Christian Grothoff <christian@grothoff.org>
Date:   Mon,  6 Jul 2026 10:50:53 +0200

Abite by RFC 6749 4.1.2 and ensure authorization codes can be used at most once

Diffstat:
Msrc/challengerdb/token_add_token.c | 25++++++++++++++++++-------
1 file changed, 18 insertions(+), 7 deletions(-)

diff --git a/src/challengerdb/token_add_token.c b/src/challengerdb/token_add_token.c @@ -28,10 +28,10 @@ enum GNUNET_DB_QueryStatus CHALLENGERDB_token_add_token (struct CHALLENGERDB_PostgresContext *ctx, - const struct CHALLENGER_ValidationNonceP *nonce, - const struct CHALLENGER_AccessTokenP *token, - struct GNUNET_TIME_Relative token_expiration, - struct GNUNET_TIME_Relative address_expiration) + const struct CHALLENGER_ValidationNonceP *nonce, + const struct CHALLENGER_AccessTokenP *token, + struct GNUNET_TIME_Relative token_expiration, + struct GNUNET_TIME_Relative address_expiration) { struct GNUNET_TIME_Absolute ge = GNUNET_TIME_relative_to_absolute (token_expiration); @@ -43,17 +43,28 @@ CHALLENGERDB_token_add_token (struct CHALLENGERDB_PostgresContext *ctx, GNUNET_PQ_query_param_end }; + /* Redemption must be atomic and one-shot (RFC 6749 4.1.2): consume the + validation by deleting it as we mint the token, so the same authorization + code cannot be replayed to mint additional tokens. A replay finds no + matching validations row and thus inserts no token (NO_RESULTS), which the + caller maps to 'invalid_grant'. The 'address IS NOT NULL' guard avoids + violating the tokens.address NOT NULL constraint (and only consumes a + validation that actually carries a solved address). */ PREPARE (ctx, "token_add_token", - "INSERT INTO tokens" + "WITH consumed AS (" + " DELETE FROM validations" + " WHERE nonce=$1" + " AND address IS NOT NULL" + " RETURNING address, last_tx_time" + ") INSERT INTO tokens" " (access_token" " ,address" " ,token_expiration_time" " ,address_expiration_time" ") SELECT" " $2, address, $3, $4 + last_tx_time" - " FROM validations" - " WHERE nonce=$1;"); + " FROM consumed;"); return GNUNET_PQ_eval_prepared_non_select (ctx->conn, "token_add_token", params);