feat: add Personal Access Token authentication with project scoping - #41
Open
zajca wants to merge 2 commits into
Open
feat: add Personal Access Token authentication with project scoping#41zajca wants to merge 2 commits into
zajca wants to merge 2 commits into
Conversation
Both the JDBC driver and the VSCode extension accepted only a project-scoped Storage API token sent in X-StorageApi-Token. They now also accept a user-scoped Personal Access Token, which Connection authenticates as a bearer credential and scopes per request via X-KBC-ProjectId. The credential kind is detected from the kbc_pat_ prefix, so existing connections keep working with no configuration change. The JDBC driver also takes an explicit `auth=token|pat` override. JDBC driver: - New com.keboola.jdbc.auth package. AuthProvider.authHeaders() is resolved per request (and re-resolved on every retry attempt) rather than captured in the constructor, so a credential that expires can be renewed without touching the HTTP clients. StorageTokenAuthProvider and PatAuthProvider are immutable and redact the credential in toString(). - All three HTTP clients take an AuthProvider instead of a token String; StorageApiClient.getToken() is replaced by getAuthProvider(). - New ProgrammaticAuthClient for GET /v1/auth/pat, which is not a storage route and therefore carries the bearer only. HTTP 404 there means programmatic auth is disabled on the stack, 401 means the token is invalid. - New `project` property. When absent for a PAT, the driver takes the union of the accessible projects across the returned items -- a derived token can never exceed its parent, so that union is the caller's own access set. One project auto-selects, several fail listing them, none fails as an auth error. - getPropertyInfo exposes `auth` and `project`, populating project choices from the PAT. workspace is no longer advertised as required, matching resolveWorkspaceId auto-selecting the newest workspace. - Host URL normalization moved to HostUrls so ProgrammaticAuthClient shares it. Behaviour is unchanged: plaintext http:// is honored for loopback only, any remote http:// base is upgraded to https:// because a credential rides on every request. VSCode extension: - New src/auth.ts owns credential detection, header construction and project discovery, shared by the extension host and the language server so both report the same diagnosis. - New optional projectId connection field, selected via QuickPick in parseBeforeSaveConnection when a PAT reaches more than one project. - Project ids stay strings end to end; they can exceed the safe integer range. Verified: 526 JDBC unit tests pass. The extension builds and its sources and test sources typecheck; its test suite could not be executed locally because vscode-test cannot download VS Code in this environment, so CI is the first runtime gate for it.
KeboolaDriverIT builds its connection properties from the environment in two places. Both now go through one helper that also honours KEBOOLA_PROJECT, so the suite can run against a Personal Access Token that reaches several projects.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
Both subprojects accepted only a project-scoped Storage API token (
X-StorageApi-Token). They now also accept a user-scoped Personal Access Token, which Connection authenticates as a bearer credential and scopes per request viaX-KBC-ProjectId.The credential kind is detected from the
kbc_pat_prefix, so existing connections keep working with no configuration change. The JDBC driver additionally takes an explicitauth=token|patoverride.This is the first of two PRs. The second adds programmatic sessions (PKCE + device code) on top of the same abstraction.
Observable difference
projectproperty (JDBC) / Project ID field (VSCode), auto-detected when the token reaches exactly one projectworkspaceadvertised as requiredServer-side facts this relies on
Verified against
keboola/connection, not assumed:Authorization: Bearer; every Storage API path additionally requiresX-KBC-ProjectId(BearerTokenAuthenticator). A project outside scope is 403.GET /v1/auth/patreturns{items: [...]}, each item carrying a live resolvedprojectsarray — populated even for an{"all": true}scope. It is a/v1/auth/*route, not a storage route, so it must not carry the project header.projectsacross items is exactly the caller's own access set. The driver never needs to identify which item is "self"./v1/auth/*returns 404, not 403. Both clients translate that into "not enabled on this stack" rather than a generic HTTP error.GET /v1/auth/token/introspectis session-only and returns 403 for a PAT bearer, which is why PAT metadata comes from/v1/auth/pat.Design notes
AuthProvider.authHeaders()is resolved per request, and re-resolved on every retry attempt, rather than captured in a constructor. Nothing in this PR needs that — a PAT does not expire mid-connection — but it is the seam the next PR's refreshable session credential plugs into without touching the HTTP clients.Host URL normalization moved to
HostUrlssoProgrammaticAuthClientshares it withStorageApiClient. Behaviour is unchanged and was verified by diffing executable statements against the original, not by eye. It is a security control: plaintexthttp://is honored for loopback only, and any remotehttp://base is upgraded tohttps://because a credential rides on every request.HostUrlsTestcovers it directly, including fail-closed cases such ashttp://localhost.evil.example.com,http://localhost@evil.example.comandhttp://evil.example.com/localhost, all of which upgrade.Project ids are
long/string everywhere. They can exceedInteger.MAX_VALUE, and the VSCode side keeps them strings end to end to stay clear of the JS safe integer range.Verification
maven:3.9-eclipse-temurin-21image against the module source, because Maven is not installed on the machine this was developed on.npm ci,npm run compileandtsc -p tsconfig.test.jsonall succeed, andtsc --noEmitreports no new errors versusmain(the 19 pre-existing ones inls/queries.tsandls/driver.tsare unchanged;tsupdoes not typecheck, which is why they exist onmain).vscode-testcould not download VS Code in this environment. CI runsxvfb-run -a npm test, so this PR's CI run is the first runtime gate for the 206 extension tests. Please confirm it is green before merging.Follow-ups, deliberately not in this PR
http://::1without a port is not recognized as loopback and gets upgraded, because the port split at the last colon leaves":". It fails closed, so it is not a hole, and it predates this PR;http://[::1]is the reliable spelling.HostUrlsTestasserts both.readOnly: trueon a PAT is rejected at issuance by Connection until runtime enforcement ships, so the clients do not surface it.