Skip to content

feat: store credential expiration epoch in secret for proactive refresh#157

Merged
Tmonster merged 1 commit into
duckdb:mainfrom
HaoXuAI:feat/store-credential-expiration
Jun 24, 2026
Merged

feat: store credential expiration epoch in secret for proactive refresh#157
Tmonster merged 1 commit into
duckdb:mainfrom
HaoXuAI:feat/store-credential-expiration

Conversation

@HaoXuAI

@HaoXuAI HaoXuAI commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Problem

When the credential_chain provider creates a secret with web_identity or sts chains, the STS response includes an Expiration timestamp — but the extension only stores key_id, secret, and session_token. The expiration is discarded.

Consumers (e.g., duckdb-iceberg) that need to refresh credentials have no way to know when they expire, and must resort to fixed-interval timers (e.g., refresh every 300s regardless of actual TTL).

Fix

Store credentials.GetExpiration() as expiration_epoch (epoch seconds as BIGINT) in the secret_map when the expiration is non-empty. This is backwards-compatible — existing consumers that don't read it are unaffected.

Usage by consumers

Value expiry_val;
if (kv_secret.TryGetValue("expiration_epoch", expiry_val)) {
    int64_t expires_at = expiry_val.GetValue<int64_t>();
    int64_t now = std::chrono::duration_cast<std::chrono::seconds>(
        std::chrono::system_clock::now().time_since_epoch()).count();
    int64_t ttl = expires_at - created_at;
    if ((expires_at - now) < ttl * 0.2) {
        // Refresh — less than 20% TTL remaining
    }
}

Related

STS AssumeRoleWithWebIdentity returns an Expiration timestamp, but
the secret only stored key_id/secret/session_token — discarding the
expiration. Consumers (duckdb-iceberg) had no way to know when creds
expire and resorted to fixed-interval refresh timers.

Store credentials.GetExpiration() as 'expiration_epoch' (epoch seconds)
in the secret_map. Consumers can now refresh at ~80% TTL instead of
guessing with arbitrary intervals.
@HaoXuAI
HaoXuAI force-pushed the feat/store-credential-expiration branch from 65d3190 to aec765a Compare June 20, 2026 08:15

@Tmonster Tmonster left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks! Just a quick comment

Comment thread src/aws_secret.cpp
// can refresh proactively at ~80% TTL instead of guessing with a fixed timer.
auto expiration = credentials.GetExpiration();
if (expiration != Aws::Utils::DateTime()) {
result->secret_map["expiration_epoch"] = Value::BIGINT(expiration.Seconds());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this used consumed anywhere? We are planning on fixing up our secret refresh functionality soon, so happy to have this in, but I don't think this is inspected anywhere else (i.e duckdb-httpfs won't use it, and I don't see it used in your duckdb-iceberg PR)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @Tmonster .yep it's not used at all currently. But if this is supported then I can update my pr in duckdb-iceberg to use it, instead of a fixed TTL. Let me know if that makes sense or not.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fine then, we can iterate on this

@Tmonster Tmonster left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Comment thread src/aws_secret.cpp
// can refresh proactively at ~80% TTL instead of guessing with a fixed timer.
auto expiration = credentials.GetExpiration();
if (expiration != Aws::Utils::DateTime()) {
result->secret_map["expiration_epoch"] = Value::BIGINT(expiration.Seconds());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fine then, we can iterate on this

@Tmonster
Tmonster merged commit ad32ec8 into duckdb:main Jun 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants