mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-28 00:02:42 +00:00
The lazy on-fetch OAuth token refresh persisted the new access token with a raw
`UPDATE variable SET value = <db-encrypted>`, bypassing the secret-backend
abstraction. With an external secret backend (AWS Secrets Manager / Azure Key
Vault / Vault), secret reads resolve through the backend and ignore
`variable.value` entirely, so refresh advanced `account.expires_at` and updated
Postgres but never wrote the new token to the external store. Every read that
did not itself trigger a mint kept serving the frozen connect-time token, which
expired ~1h after connect (RefreshError on Google clients).
`windmill-oauth` can't depend on `windmill-store` (circular), so variable
persistence moves out of `refresh_token{,_for_account}` (which now only exchange
the token + update the `account` row and return the new token) into the
`windmill-store` callers, via a new `store_oauth_token_value` helper that writes
through the configured backend and stores the returned value (encrypted blob for
the DB backend, `$...:` marker for external backends) in `variable.value`.
If persisting the refreshed token fails (more likely now that it can be a
network write to an external backend) after the account was committed fresh,
`store_oauth_token_value` resets `expires_at` to the past and records
`refresh_error` — looking the account up via `variable.account` — so the next
fetch retries instead of serving the stale token for the whole token lifetime.
Also add `windmill-store/tests/oauth_refresh_secret_backend.rs`, an opt-in e2e
regression suite (RUN_SECRET_BACKEND_E2E / RUN_AWS_SM_TESTS) covering database
and external (AWS SM via LocalStack) backends plus the self-healing reset.
Verified against Postgres + LocalStack: 3 passed.
EE companion (oauth_refresh_ee.rs: 3 refresh paths) merged via #607; this OSS
half completes the fix (ee-repo-ref already at EE main 481ea7f).
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
45 lines
1.2 KiB
Rust
45 lines
1.2 KiB
Rust
/*
|
|
* Author: Windmill Labs, Inc
|
|
* Copyright: Windmill Labs, Inc 2024
|
|
* This file and its contents are licensed under the AGPLv3 License.
|
|
* Please see the included NOTICE for copyright information and
|
|
* LICENSE-AGPL for a copy of the license.
|
|
*/
|
|
|
|
#[cfg(feature = "private")]
|
|
pub use crate::oauth_refresh_ee::_refresh_token;
|
|
|
|
#[cfg(not(feature = "private"))]
|
|
use sqlx::{Postgres, Transaction};
|
|
#[cfg(not(feature = "private"))]
|
|
use windmill_common::db::DB;
|
|
#[cfg(not(feature = "private"))]
|
|
use windmill_common::error;
|
|
|
|
#[cfg(not(feature = "private"))]
|
|
pub async fn _refresh_token<'c>(
|
|
tx: Transaction<'c, Postgres>,
|
|
path: &str,
|
|
w_id: &str,
|
|
id: i32,
|
|
db: &DB,
|
|
) -> error::Result<String> {
|
|
let token = windmill_oauth::refresh_token(
|
|
tx,
|
|
w_id,
|
|
id,
|
|
db,
|
|
&*windmill_oauth::OAUTH_CLIENTS.load(),
|
|
&windmill_oauth::OAUTH_HTTP_CLIENT,
|
|
include_str!("../../oauth_connect.json"),
|
|
)
|
|
.await?;
|
|
|
|
// Persist the refreshed token through the configured secret backend so an
|
|
// external backend (Vault / Azure KV / AWS Secrets Manager) is updated too,
|
|
// not just the in-DB variable mirror.
|
|
crate::secret_backend_ext::store_oauth_token_value(db, w_id, path, &token).await?;
|
|
|
|
Ok(token)
|
|
}
|