diff --git a/apps/dashboard/src/components/provider-icons.tsx b/apps/dashboard/src/components/provider-icons.tsx
index 18568984..2027f62f 100644
--- a/apps/dashboard/src/components/provider-icons.tsx
+++ b/apps/dashboard/src/components/provider-icons.tsx
@@ -7,6 +7,7 @@ import type { IconSvgProps, SimpleIconData } from "@onequery/ui/icons/svg-icon";
import {
IconDatabase,
IconHelpCircle,
+ IconKey,
IconNotebook,
IconTerminal2,
} from "@tabler/icons-react";
@@ -216,6 +217,12 @@ function E2BIcon(props: ProviderIconProps) {
);
}
+function OnePasswordIcon(props: ProviderIconProps) {
+ return (
+
+ );
+}
+
function MicrosoftClarityIcon({ size = 24, ...props }: ProviderIconProps) {
return (
`. The s
| Databases | `postgres`, `supabase`, `mysql`, `mongodb` |
| Warehouses | `snowflake`, `bigquery`, `aws_athena_connector`, `motherduck`, `cloudflare_d1` |
| Observability | `sentry`, `laminar`, `cloudflare_workers_observability` |
-| Developer workflow | `github`, `linear`, `jira`, `confluence`, `vercel`, `discord` |
+| Developer workflow | `github`, `linear`, `jira`, `confluence`, `vercel`, `discord`, `onepassword` |
| Product analytics | `ga`, `amplitude`, `mixpanel`, `posthog`, `microsoft_clarity`, `cloudflare_web_analytics` |
| Marketing | `google_search_console`, `amazon_ads`, `linkedin_ads`, `tiktok_marketing`, `sendgrid` |
| Productivity | `airtable`, `cal`, `granola` |
diff --git a/apps/landing/src/shared/icons/brands.tsx b/apps/landing/src/shared/icons/brands.tsx
index 7491d25b..046cf556 100644
--- a/apps/landing/src/shared/icons/brands.tsx
+++ b/apps/landing/src/shared/icons/brands.tsx
@@ -143,6 +143,33 @@ function E2BIcon({ size, ...props }: IconSvgProps) {
);
}
+function OnePasswordIcon({ size, ...props }: IconSvgProps) {
+ return (
+
+
+
+
+ );
+}
+
function MicrosoftClarityIcon({ size, ...props }: IconSvgProps) {
return (
credentialSchemaMap > matches supported provider
"mongodb",
"motherduck",
"mysql",
+ "onepassword",
"postgres",
"posthog",
"sendgrid",
diff --git a/packages/db/src/connection-guide.ts b/packages/db/src/connection-guide.ts
index c4102d23..d8c6c1f8 100644
--- a/packages/db/src/connection-guide.ts
+++ b/packages/db/src/connection-guide.ts
@@ -522,6 +522,25 @@ export const SOURCE_CONNECT_PROVIDER_GUIDES: SourceConnectProviderGuide[] = [
},
},
},
+ {
+ provider: "onepassword",
+ summary:
+ "Connect 1Password through a self-hosted Connect Server API endpoint.",
+ steps: [
+ "Deploy or choose the 1Password Connect Server that can read the target vaults.",
+ "Create a Connect access token scoped to the vaults and items OneQuery should inspect.",
+ "Set `credentials.apiBaseUrl` to the Connect Server origin, for example `https://connect.example.com`.",
+ "Source API calls are read-only; use selectors such as `/v1/vaults` and `/v1/vaults/{vaultUUID}/items`.",
+ ],
+ exampleInput: {
+ sourceKey: "onepassword_main",
+ credentials: {
+ type: "onepassword",
+ apiBaseUrl: "https://connect.example.com",
+ accessToken: "onepassword_connect_token",
+ },
+ },
+ },
{
provider: "microsoft_clarity",
summary: "Connect Microsoft Clarity with a project Data Export API token.",
diff --git a/packages/db/src/credentials.test.ts b/packages/db/src/credentials.test.ts
index 696dced5..f683e81d 100644
--- a/packages/db/src/credentials.test.ts
+++ b/packages/db/src/credentials.test.ts
@@ -35,6 +35,7 @@ import {
MotherDuckCredentialsSchema,
MongoDBCredentialsSchema,
MySQLCredentialsSchema,
+ OnePasswordCredentialsSchema,
normalizeEnvVarName,
PostgresCredentialsSchema,
PostHogCredentialsSchema,
@@ -73,6 +74,7 @@ import type {
MotherDuckCredentials,
MongoDBCredentials,
MySQLCredentials,
+ OnePasswordCredentials,
PostgresCredentials,
PostHogCredentials,
SendGridCredentials,
@@ -1737,6 +1739,38 @@ describe("credentials schemas", () => {
});
});
+ describe("OnePasswordCredentialsSchema", () => {
+ it("validates 1Password credentials", () => {
+ const credentials: OnePasswordCredentials = {
+ accessToken: "onepassword_connect_token",
+ apiBaseUrl: "https://connect.example.com",
+ type: "onepassword",
+ };
+
+ const result = OnePasswordCredentialsSchema.safeParse(credentials);
+ expect(result.success).toBe(true);
+ });
+
+ it("rejects missing access token", () => {
+ const result = OnePasswordCredentialsSchema.safeParse({
+ apiBaseUrl: "https://connect.example.com",
+ type: "onepassword",
+ });
+
+ expect(result.success).toBe(false);
+ });
+
+ it("rejects invalid API base URL", () => {
+ const result = OnePasswordCredentialsSchema.safeParse({
+ accessToken: "onepassword_connect_token",
+ apiBaseUrl: "not-a-url",
+ type: "onepassword",
+ });
+
+ expect(result.success).toBe(false);
+ });
+ });
+
describe("MicrosoftClarityCredentialsSchema", () => {
it("validates Microsoft Clarity credentials", () => {
const credentials: MicrosoftClarityCredentials = {
@@ -1938,6 +1972,12 @@ describe("credentials schemas", () => {
expect(credentialSchemaMap.e2b).toBe(E2BCredentialsSchema);
});
+ it("should map onepassword to OnePasswordCredentialsSchema", () => {
+ expect(credentialSchemaMap.onepassword).toBe(
+ OnePasswordCredentialsSchema
+ );
+ });
+
it("should map slack to SlackCredentialsSchema", () => {
expect(credentialSchemaMap.slack).toBe(SlackCredentialsSchema);
});
@@ -2217,6 +2257,17 @@ describe("credentials schemas", () => {
expect(result.type).toBe("microsoft_clarity");
});
+ it("should validate 1Password credentials", () => {
+ const credentials = {
+ accessToken: "onepassword_connect_token",
+ apiBaseUrl: "https://connect.example.com",
+ type: "onepassword",
+ };
+
+ const result = validateCredentials(credentials);
+ expect(result.type).toBe("onepassword");
+ });
+
it("should validate Cloudflare Web Analytics credentials", () => {
const credentials = {
accountId: "023e105f4ecef8ad9ca31a8372d0c353",
diff --git a/packages/db/src/credentials.ts b/packages/db/src/credentials.ts
index ba252a79..537ed30a 100644
--- a/packages/db/src/credentials.ts
+++ b/packages/db/src/credentials.ts
@@ -445,6 +445,19 @@ export type MicrosoftClarityCredentials = z.infer<
typeof MicrosoftClarityCredentialsSchema
>;
+export const OnePasswordCredentialsSchema = z.object({
+ accessToken: requiredOpaqueString("Access token is required"),
+ apiBaseUrl: trimmedUrl(
+ "API base URL is required",
+ "API base URL must be a valid URL"
+ ).transform((value) => value.replace(/\/+$/, "")),
+ type: z.literal("onepassword"),
+});
+
+export type OnePasswordCredentials = z.infer<
+ typeof OnePasswordCredentialsSchema
+>;
+
export const CloudflareD1CredentialsSchema = z.object({
accountId: trimmedString("Account ID is required"),
apiBaseUrl: optionalTrimmedUrl("API base URL must be a valid URL"),
@@ -537,6 +550,7 @@ export const CredentialsSchema = z.union([
VercelCredentialsSchema,
E2BCredentialsSchema,
MicrosoftClarityCredentialsSchema,
+ OnePasswordCredentialsSchema,
CloudflareD1CredentialsSchema,
CloudflareWorkersObservabilityCredentialsSchema,
CloudflareWebAnalyticsCredentialsSchema,
@@ -604,6 +618,7 @@ export const credentialSchemaMap = {
motherduck: MotherDuckCredentialsSchema,
mongodb: MongoDBCredentialsSchema,
mysql: MySQLCredentialsSchema,
+ onepassword: OnePasswordCredentialsSchema,
postgres: PostgresCredentialsSchema,
posthog: PostHogCredentialsSchema,
sendgrid: SendGridCredentialsSchema,
diff --git a/packages/db/src/schema/__snapshots__/data-sources.test.ts.snap b/packages/db/src/schema/__snapshots__/data-sources.test.ts.snap
index 2f97cfce..7ba420d5 100644
--- a/packages/db/src/schema/__snapshots__/data-sources.test.ts.snap
+++ b/packages/db/src/schema/__snapshots__/data-sources.test.ts.snap
@@ -33,6 +33,7 @@ exports[`data-sources schema > matches provider type snapshots 1`] = `
"jira",
"vercel",
"e2b",
+ "onepassword",
"microsoft_clarity",
"linear",
"cloudflare_workers_observability",
@@ -69,6 +70,7 @@ exports[`data-sources schema > matches provider type snapshots 1`] = `
"jira",
"vercel",
"e2b",
+ "onepassword",
"microsoft_clarity",
"linear",
"cloudflare_workers_observability",
diff --git a/packages/db/src/source-providers.ts b/packages/db/src/source-providers.ts
index aedeb700..5feb8fc8 100644
--- a/packages/db/src/source-providers.ts
+++ b/packages/db/src/source-providers.ts
@@ -26,6 +26,7 @@ import {
MotherDuckCredentialsSchema,
MongoDBCredentialsSchema,
MySQLCredentialsSchema,
+ OnePasswordCredentialsSchema,
PostgresCredentialsSchema,
PostHogCredentialsSchema,
SendGridCredentialsSchema,
@@ -981,6 +982,37 @@ export const SOURCE_PROVIDER_REGISTRY = {
},
},
},
+ onepassword: {
+ label: "1Password",
+ credentialSchema: OnePasswordCredentialsSchema,
+ credentialType: "onepassword",
+ connectable: true,
+ analysisSource: true,
+ queryInterface: false,
+ sourceApiInterface: true,
+ testable: false,
+ dashboardConnectable: true,
+ dashboardCredentialForm: "json",
+ publicCategory: "Developer workflow",
+ guide: {
+ summary:
+ "Connect 1Password through a self-hosted Connect Server API endpoint.",
+ steps: [
+ "Deploy or choose the 1Password Connect Server that can read the target vaults.",
+ "Create a Connect access token scoped to the vaults and items OneQuery should inspect.",
+ "Set `credentials.apiBaseUrl` to the Connect Server origin, for example `https://connect.example.com`.",
+ "Source API calls are read-only; use selectors such as `/v1/vaults` and `/v1/vaults/{vaultUUID}/items`.",
+ ],
+ exampleInput: {
+ sourceKey: "onepassword_main",
+ credentials: {
+ type: "onepassword",
+ apiBaseUrl: "https://connect.example.com",
+ accessToken: "onepassword_connect_token",
+ },
+ },
+ },
+ },
microsoft_clarity: {
label: "Microsoft Clarity",
credentialSchema: MicrosoftClarityCredentialsSchema,
diff --git a/packages/server/src/source-api/adapters/onepassword.ts b/packages/server/src/source-api/adapters/onepassword.ts
new file mode 100644
index 00000000..6fa9af21
--- /dev/null
+++ b/packages/server/src/source-api/adapters/onepassword.ts
@@ -0,0 +1,43 @@
+import type { OnePasswordCredentials } from "@onequery/db/server";
+
+import { createSimpleRestSourceApiAdapter } from "./simple-rest";
+
+const ONEPASSWORD_DESCRIPTOR_VERSION = "onepassword.v1";
+
+export const onePasswordSourceApiAdapter =
+ createSimpleRestSourceApiAdapter({
+ allowedMethods: ["GET"],
+ apiBaseUrl: (credentials) => credentials.apiBaseUrl,
+ auth: (credentials) => ({
+ token: credentials.accessToken,
+ type: "bearer",
+ }),
+ buildExamples: (sourceKey) => [
+ {
+ command: `onequery api --source ${sourceKey} /v1/vaults`,
+ description: "List vaults visible to the connected Connect token.",
+ label: "List vaults",
+ },
+ {
+ command: `onequery api --source ${sourceKey} /v1/vaults//items`,
+ description: "List items in one vault.",
+ label: "List vault items",
+ },
+ {
+ command: `onequery api --source ${sourceKey} /v1/vaults//items/`,
+ description: "Fetch one item from a vault.",
+ label: "Get item",
+ },
+ ],
+ descriptorVersion: ONEPASSWORD_DESCRIPTOR_VERSION,
+ notes: [
+ "1Password requests are sent to the configured Connect Server API base URL with Authorization bearer auth.",
+ "Only GET requests are supported. Item and vault mutations are intentionally excluded.",
+ "Use `params` in the field patch for Connect API query parameters such as `filter`.",
+ ],
+ operationNotes: [
+ "Selectors should be Connect API paths such as `/v1/vaults` or `/v1/vaults/{vaultUUID}/items`.",
+ ],
+ provider: "onepassword",
+ providerLabel: "1Password",
+ });
diff --git a/packages/server/src/source-api/adapters/simple-rest-providers.test.ts b/packages/server/src/source-api/adapters/simple-rest-providers.test.ts
index 33a769cc..635f6bd8 100644
--- a/packages/server/src/source-api/adapters/simple-rest-providers.test.ts
+++ b/packages/server/src/source-api/adapters/simple-rest-providers.test.ts
@@ -13,6 +13,7 @@ import { granolaSourceApiAdapter } from "./granola";
import { jiraSourceApiAdapter } from "./jira";
import { linkedInAdsSourceApiAdapter } from "./linkedin-ads";
import { microsoftClaritySourceApiAdapter } from "./microsoft-clarity";
+import { onePasswordSourceApiAdapter } from "./onepassword";
import { sendGridSourceApiAdapter } from "./sendgrid";
import { tiktokMarketingSourceApiAdapter } from "./tiktok-marketing";
import { vercelSourceApiAdapter } from "./vercel";
@@ -822,6 +823,98 @@ describe("simple REST source API providers", () => {
).rejects.toThrow("Unsupported HTTP method override: POST");
});
+ it("executes 1Password read-only requests with bearer auth", async () => {
+ const fetchMock = vi.fn().mockResolvedValue(
+ new Response(JSON.stringify({ vaults: [] }), {
+ headers: {
+ "content-type": "application/json",
+ },
+ status: 200,
+ })
+ );
+ globalThis.fetch = fetchMock as unknown as typeof fetch;
+
+ const source: PreparedSourceConnection = {
+ credentials: {
+ accessToken: "op_connect_token",
+ apiBaseUrl: "https://connect.example.com",
+ type: "onepassword",
+ },
+ displayName: "1Password",
+ id: "source_16",
+ provider: "onepassword",
+ sourceKey: "onepassword-main",
+ };
+ const descriptor = await onePasswordSourceApiAdapter.describe({
+ actor,
+ source,
+ });
+ const operation = descriptor.operations[0];
+ expect(operation?.methodPolicy.allowedMethods).toEqual(["GET"]);
+
+ const plan = await onePasswordSourceApiAdapter.normalize({
+ actor,
+ descriptor,
+ request: {
+ body: { kind: "none" },
+ fieldPatch: {
+ params: {
+ filter: 'title eq "Production"',
+ },
+ },
+ headers: [],
+ operation: "fetch_api",
+ selector: "/v1/vaults/vault_123/items",
+ },
+ source,
+ });
+
+ expect(plan.kind).toBe("http_request");
+ if (plan.kind !== "http_request") {
+ throw new Error("expected HTTP request plan");
+ }
+ expect(plan.url).toBe(
+ "https://connect.example.com/v1/vaults/vault_123/items?filter=title+eq+%22Production%22"
+ );
+
+ const response = await onePasswordSourceApiAdapter.execute({
+ actor,
+ prepared: {
+ ...plan,
+ bodyKind: "none",
+ bodyPaths: [],
+ headerNames: [],
+ preparedBinding: "binding",
+ },
+ source,
+ });
+
+ expect(response.status).toBe(200);
+ const [calledUrl, calledInit] = fetchMock.mock.calls[0] ?? [];
+ expect(String(calledUrl)).toBe(
+ "https://connect.example.com/v1/vaults/vault_123/items?filter=title+eq+%22Production%22"
+ );
+ expect(calledInit?.headers).toMatchObject({
+ Authorization: "Bearer op_connect_token",
+ });
+
+ await expect(
+ onePasswordSourceApiAdapter.normalize({
+ actor,
+ descriptor,
+ request: {
+ body: { kind: "none" },
+ fieldPatch: undefined,
+ headers: [],
+ methodOverride: "POST",
+ operation: "fetch_api",
+ selector: "/v1/vaults/vault_123/items",
+ },
+ source,
+ })
+ ).rejects.toThrow("Unsupported HTTP method override: POST");
+ });
+
it("normalizes Microsoft Clarity live insights requests", async () => {
const source: PreparedSourceConnection = {
credentials: {
diff --git a/packages/server/src/source-api/registry.ts b/packages/server/src/source-api/registry.ts
index 73d257e2..c1a5ca58 100644
--- a/packages/server/src/source-api/registry.ts
+++ b/packages/server/src/source-api/registry.ts
@@ -19,6 +19,7 @@ import { linkedInAdsSourceApiAdapter } from "./adapters/linkedin-ads";
import { microsoftClaritySourceApiAdapter } from "./adapters/microsoft-clarity";
import { mixpanelSourceApiAdapter } from "./adapters/mixpanel";
import { mongodbSourceApiAdapter } from "./adapters/mongodb";
+import { onePasswordSourceApiAdapter } from "./adapters/onepassword";
import { postHogSourceApiAdapter } from "./adapters/posthog";
import { sendGridSourceApiAdapter } from "./adapters/sendgrid";
import { sentrySourceApiAdapter } from "./adapters/sentry";
@@ -88,6 +89,7 @@ export const sourceApiRegistry = createSourceApiRegistry([
microsoftClaritySourceApiAdapter,
mixpanelSourceApiAdapter,
mongodbSourceApiAdapter,
+ onePasswordSourceApiAdapter,
postHogSourceApiAdapter,
sendGridSourceApiAdapter,
sentrySourceApiAdapter,
diff --git a/packages/ui/src/data-sources/connection-guides/index.ts b/packages/ui/src/data-sources/connection-guides/index.ts
index 24fc0a3f..54b049e9 100644
--- a/packages/ui/src/data-sources/connection-guides/index.ts
+++ b/packages/ui/src/data-sources/connection-guides/index.ts
@@ -46,6 +46,7 @@ export const GUIDE_CONTENT: Record<
motherduck: motherduckGuideContent,
mongodb: mongodbGuideContent,
mysql: mysqlGuideContent,
+ onepassword: { providerLabel: "1Password" },
postgres: postgresGuideContent,
posthog: posthogGuideContent,
sendgrid: sendGridGuideContent,
diff --git a/packages/ui/src/data-sources/connection-guides/types.ts b/packages/ui/src/data-sources/connection-guides/types.ts
index 4a0266ff..9019545b 100644
--- a/packages/ui/src/data-sources/connection-guides/types.ts
+++ b/packages/ui/src/data-sources/connection-guides/types.ts
@@ -14,6 +14,7 @@ export type DataSourceConnectionGuideProvider =
| "motherduck"
| "mongodb"
| "mysql"
+ | "onepassword"
| "postgres"
| "posthog"
| "sendgrid"