Skip to content

remove the tokens service; use the same strategy for target access tokens (bentocache) as with organization access tokens#8212

Draft
n1ru4l wants to merge 1 commit into
mainfrom
feat-remove-tokens-service
Draft

remove the tokens service; use the same strategy for target access tokens (bentocache) as with organization access tokens#8212
n1ru4l wants to merge 1 commit into
mainfrom
feat-remove-tokens-service

Conversation

@n1ru4l

@n1ru4l n1ru4l commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Nuke the tokens service and use the same strategy for reading target (legacy) access tokens from postgres/redis cache with a bentocache powered module shared between all services (usage, server) that need to read access tokens.

This removes quite a lot of code and I wanted to do this for a long time. 🙏

@n1ru4l n1ru4l force-pushed the feat-remove-tokens-service branch from 183b276 to 0ef5f17 Compare July 12, 2026 14:39
@github-actions

github-actions Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

🚀 Snapshot Release (alpha)

The latest changes of this PR are available as alpha on npm (based on the declared changesets):

Package Version Info
hive 11.5.0-alpha-20260712152759-5bf6de36e8ac5e1f844f6ba4d49863bca63c3875 npm ↗︎ unpkg ↗︎

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request deprecates and removes the standalone tokens service, migrating its token validation, storage, and caching logic directly into the api service as TargetTokenStorage and TargetTokenCache (powered by BentoCache). The usage service has been refactored to consume this cache directly, eliminating inter-service HTTP/tRPC overhead. Feedback on the changes highlights a critical runtime issue where the new TargetTokenCache is not exported in the api package's entry points, and a correctness bug where double-hashing in touchTokenBySecret prevents the last_used_at timestamp from updating in the database.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +14 to +15
"./modules/schema/providers/schema-version-store": "./src/modules/schema/providers/schema-version-store.ts",
"./modules/token/providers/target-token-storage": "./src/modules/token/providers/target-token-storage.ts"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

critical

The TargetTokenCache provider is imported by the usage service from @hive/api/modules/token/providers/target-token-cache. However, this subpath is not listed in the exports field of @hive/api/package.json. Because Node.js restricts subpath imports to only those explicitly declared in exports, attempting to import it from another package will fail at runtime. Please add ./modules/token/providers/target-token-cache to the exports.

Suggested change
"./modules/schema/providers/schema-version-store": "./src/modules/schema/providers/schema-version-store.ts",
"./modules/token/providers/target-token-storage": "./src/modules/token/providers/target-token-storage.ts"
"./modules/schema/providers/schema-version-store": "./src/modules/schema/providers/schema-version-store.ts",
"./modules/token/providers/target-token-cache": "./src/modules/token/providers/target-token-cache.ts",
"./modules/token/providers/target-token-storage": "./src/modules/token/providers/target-token-storage.ts"

Comment on lines +130 to +140
static touchTokenBySecret(deps: { pool: CommonQueryMethods }) {
return async function touchTokenBySecret(token: string) {
await deps.pool.query(psql`
UPDATE "tokens"
SET "last_used_at" = NOW()
WHERE
"token" = ${hashTargetToken(token)}
AND "deleted_at" IS NULL
`);
};
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

The touchTokenBySecret method currently takes a token, hashes it using hashTargetToken, and then updates the database. However, in TargetTokenCache.get, the value passed to it is result.token, which is already the hashed token from the database. This causes the token to be double-hashed, meaning the UPDATE query will match 0 rows and last_used_at will never be updated. Changing this to touchTokenByHash avoids redundant hashing (improving performance) and fixes the correctness bug.

Suggested change
static touchTokenBySecret(deps: { pool: CommonQueryMethods }) {
return async function touchTokenBySecret(token: string) {
await deps.pool.query(psql`
UPDATE "tokens"
SET "last_used_at" = NOW()
WHERE
"token" = ${hashTargetToken(token)}
AND "deleted_at" IS NULL
`);
};
}
static touchTokenByHash(deps: { pool: CommonQueryMethods }) {
return async function touchTokenByHash(hashedToken: string) {
await deps.pool.query(psql`
UPDATE "tokens"
SET "last_used_at" = NOW()
WHERE
"token" = ${hashedToken}
AND "deleted_at" IS NULL
`);
};
}

Comment on lines +54 to +59
}).then(result => {
if (result) {
void TargetTokenStorage.touchTokenBySecret({ pool: this.pool })(result.token).catch(() => {});
}
return result
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Update this call to use the new touchTokenByHash method with the already computed hashedToken to avoid double-hashing and ensure last_used_at is correctly updated.

Suggested change
}).then(result => {
if (result) {
void TargetTokenStorage.touchTokenBySecret({ pool: this.pool })(result.token).catch(() => {});
}
return result
});
}).then(result => {
if (result) {
void TargetTokenStorage.touchTokenByHash({ pool: this.pool })(hashedToken).catch(() => {});
}
return result;
});

Comment on lines +175 to +177
// touch the token so it has a date
await tokenStorage.touchTokens({ tokens: [{ token: record.token, date: new Date() }] });
const result = await readTokenInfo(token.secret).then(res => res.expectNoGraphQLErrors());
await TargetTokenStorage.touchTokenBySecret({ pool })(record.token)
const result = await readTokenInfo(token).then(res => res.expectNoGraphQLErrors());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Update the test to use touchTokenByHash since record.token is already the hashed token, ensuring the test correctly verifies the last_used_at behavior.

Suggested change
// touch the token so it has a date
await tokenStorage.touchTokens({ tokens: [{ token: record.token, date: new Date() }] });
const result = await readTokenInfo(token.secret).then(res => res.expectNoGraphQLErrors());
await TargetTokenStorage.touchTokenBySecret({ pool })(record.token)
const result = await readTokenInfo(token).then(res => res.expectNoGraphQLErrors());
// touch the token so it has a date
await TargetTokenStorage.touchTokenByHash({ pool })(record.token)
const result = await readTokenInfo(token).then(res => res.expectNoGraphQLErrors());
References
  1. When refactoring or optimizing SQL queries, write comprehensive integration tests to verify correctness under edge cases to ensure correctness and prevent regressions.

@n1ru4l n1ru4l force-pushed the feat-remove-tokens-service branch 3 times, most recently from 57d9209 to 7a27374 Compare July 12, 2026 14:52
…kens (bentocache) as with organization access tokens
@n1ru4l n1ru4l force-pushed the feat-remove-tokens-service branch from 7a27374 to 5bf6de3 Compare July 12, 2026 15:26
@github-actions

github-actions Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

🐋 This PR was built and pushed to the following Docker images:

Targets: build

Platforms: linux/arm64

Image Tags: 11.5.0-alpha-5bf6de3, 5bf6de3, 5bf6de36e8ac5e1f844f6ba4d49863bca63c3875

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant