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