mirror of
https://github.com/lancedb/lancedb.git
synced 2026-10-23 20:22:37 +00:00
Previously, authentication.mdx only documented a subset of the existing OAuthFlowType entries. We should document all of them.
428 lines
18 KiB
Plaintext
428 lines
18 KiB
Plaintext
---
|
|
title: "Authentication"
|
|
sidebarTitle: "Authentication"
|
|
description: "Authentication modes for LanceDB Enterprise: API keys and OAuth credentials."
|
|
icon: key
|
|
keywords: ["authentication", "oauth", "api key", "authorization code", "device code", "azure managed identity", "client credentials"]
|
|
availability:
|
|
oss: unavailable
|
|
enterprise: available
|
|
summary: >-
|
|
Requests to a deployment carry an API key or an OAuth token, whichever it is
|
|
configured to accept. Embedded LanceDB has no server to sign in to; see
|
|
[Architecture](/architecture).
|
|
---
|
|
|
|
A deployment authenticates each request over a `db://` connection before
|
|
[authorization](/governance/authorization) decides what it may do.
|
|
Choose one of these methods:
|
|
|
|
- **API keys**: a long-lived shared secret passed as `api_key` on connect. Works in every SDK.
|
|
- **OAuth 2.0**: short-lived bearer tokens obtained from your identity provider, refreshed automatically by the client.
|
|
|
|
OAuth is the recommended option when you want to rotate credentials centrally,
|
|
plug into an existing identity provider, or run on Azure with managed
|
|
identities so no secret material lives on the client.
|
|
|
|
## API key {#api-key}
|
|
|
|
Pass the API key from your Enterprise tenant on `connect`. This works with
|
|
both the synchronous and asynchronous Python clients, as well as TypeScript
|
|
and Rust. Load the key from an environment variable or secret manager.
|
|
|
|
<CodeGroup>
|
|
```python Python icon="python"
|
|
import os
|
|
import lancedb
|
|
|
|
db = lancedb.connect(
|
|
uri="db://your-database-uri",
|
|
api_key=os.environ["LANCEDB_API_KEY"],
|
|
region="us-east-1",
|
|
host_override="https://your-enterprise-endpoint.com",
|
|
)
|
|
```
|
|
|
|
```typescript TypeScript icon="square-js"
|
|
import * as lancedb from "@lancedb/lancedb";
|
|
|
|
const apiKey = process.env.LANCEDB_API_KEY;
|
|
if (!apiKey) throw new Error("LANCEDB_API_KEY is required");
|
|
|
|
const db = await lancedb.connect("db://your-database-uri", {
|
|
apiKey,
|
|
region: "us-east-1",
|
|
hostOverride: "https://your-enterprise-endpoint.com",
|
|
});
|
|
```
|
|
|
|
```rust Rust icon="rust"
|
|
let api_key = std::env::var("LANCEDB_API_KEY")?;
|
|
|
|
let db = lancedb::connect("db://your-database-uri")
|
|
.api_key(&api_key)
|
|
.region("us-east-1")
|
|
.host_override("https://your-enterprise-endpoint.com")
|
|
.execute()
|
|
.await?;
|
|
```
|
|
</CodeGroup>
|
|
|
|
For Rust, enable the `remote` feature on the `lancedb` dependency to use
|
|
API key or OAuth authentication.
|
|
|
|
See [Database](/management/database#deployment) for the connection options.
|
|
|
|
## OAuth {#oauth}
|
|
|
|
The async Python, TypeScript, and Rust clients can obtain bearer tokens
|
|
from an OIDC issuer and attach them to every request. Token acquisition,
|
|
caching, and refresh are handled inside the client. Your application code
|
|
only provides the configuration.
|
|
|
|
A deployment accepts these tokens only when its administrator has configured
|
|
it with your identity provider. Ask them for the issuer URL, client ID, scopes,
|
|
and any resource or audience required by the provider. For Authorization Code,
|
|
register the loopback redirect URI with the provider. For Device Code, enable
|
|
the provider's device authorization grant for your application.
|
|
|
|
<Info>
|
|
In Python, OAuth is supported through `lancedb.connect_async`. The synchronous
|
|
`connect` entry point continues to use API key authentication for `db://`
|
|
URIs. In TypeScript, `lancedb.connect` accepts `oauthConfig` directly.
|
|
In Rust, use `.oauth_config(config)` on the connection builder.
|
|
</Info>
|
|
|
|
### Supported flows {#supported-flows}
|
|
|
|
`OAuthFlowType` (Python and TypeScript) or `OAuthFlow` (Rust) selects how the
|
|
client acquires tokens:
|
|
|
|
| Flow | Python value | TypeScript value | Rust value | When to use |
|
|
| --- | --- | --- | --- | --- |
|
|
| Client Credentials | `OAuthFlowType.CLIENT_CREDENTIALS` | `OAuthFlowType.ClientCredentials` | `OAuthFlow::ClientCredentials` | Service-to-service / machine-to-machine. Requires a client ID and client secret registered with your identity provider. |
|
|
| Authorization Code | `OAuthFlowType.AUTHORIZATION_CODE` | `OAuthFlowType.AuthorizationCode` | `OAuthFlow::AuthorizationCode(AuthorizationCodeOptions::new())` | Interactive user sign-in through a browser and local callback server. Uses S256 PKCE by default. |
|
|
| Device Code | `OAuthFlowType.DEVICE_CODE` | `OAuthFlowType.DeviceCode` | `OAuthFlow::DeviceCode` | CLI or headless sign-in. The client displays a verification URL and user code for the user to enter on another device. |
|
|
| Azure Managed Identity | `OAuthFlowType.AZURE_MANAGED_IDENTITY` | `OAuthFlowType.AzureManagedIdentity` | `OAuthFlow::AzureManagedIdentity { client_id: None }` | Azure workloads with access to the IMDS endpoint. Tokens are fetched from IMDS, so no client secret is stored on the client. |
|
|
|
|
### Configure OAuth {#configure-oauth}
|
|
|
|
Build an OAuth config and pass it on connect. Use `oauth_config` in Python and
|
|
Rust, and `oauthConfig` in TypeScript.
|
|
|
|
<CodeGroup>
|
|
```python Python icon="python"
|
|
import os
|
|
import lancedb
|
|
from lancedb.remote import OAuthConfig, OAuthFlowType
|
|
|
|
# Client Credentials (service-to-service)
|
|
oauth_config = OAuthConfig(
|
|
issuer_url="https://login.microsoftonline.com/{tenant}/v2.0",
|
|
client_id="your-application-client-id",
|
|
client_secret=os.environ["LANCEDB_OAUTH_CLIENT_SECRET"],
|
|
scopes=["api://lancedb-api/.default"],
|
|
flow=OAuthFlowType.CLIENT_CREDENTIALS,
|
|
)
|
|
|
|
db = await lancedb.connect_async(
|
|
uri="db://your-database-uri",
|
|
region="us-east-1",
|
|
host_override="https://your-enterprise-endpoint.com",
|
|
oauth_config=oauth_config,
|
|
)
|
|
```
|
|
|
|
```typescript TypeScript icon="square-js"
|
|
import * as lancedb from "@lancedb/lancedb";
|
|
import { OAuthConfig, OAuthFlowType } from "@lancedb/lancedb";
|
|
|
|
const clientSecret = process.env.LANCEDB_OAUTH_CLIENT_SECRET;
|
|
if (!clientSecret) throw new Error("LANCEDB_OAUTH_CLIENT_SECRET is required");
|
|
|
|
// Client Credentials (service-to-service)
|
|
const oauthConfig: OAuthConfig = {
|
|
issuerUrl: "https://login.microsoftonline.com/{tenant}/v2.0",
|
|
clientId: "your-application-client-id",
|
|
clientSecret,
|
|
scopes: ["api://lancedb-api/.default"],
|
|
flow: OAuthFlowType.ClientCredentials,
|
|
};
|
|
|
|
const db = await lancedb.connect("db://your-database-uri", {
|
|
region: "us-east-1",
|
|
hostOverride: "https://your-enterprise-endpoint.com",
|
|
oauthConfig,
|
|
});
|
|
```
|
|
|
|
```rust Rust icon="rust"
|
|
use lancedb::remote::{OAuthConfig, OAuthFlow};
|
|
|
|
// Client Credentials (service-to-service)
|
|
let oauth_config = OAuthConfig {
|
|
issuer_url: "https://login.microsoftonline.com/{tenant}/v2.0".into(),
|
|
client_id: "your-application-client-id".into(),
|
|
client_secret: Some(std::env::var("LANCEDB_OAUTH_CLIENT_SECRET")?),
|
|
scopes: vec!["api://lancedb-api/.default".into()],
|
|
flow: OAuthFlow::ClientCredentials,
|
|
client_auth_method: None,
|
|
resource: None,
|
|
audience: None,
|
|
refresh_buffer_secs: None,
|
|
token_cache: None,
|
|
};
|
|
|
|
let db = lancedb::connect("db://your-database-uri")
|
|
.region("us-east-1")
|
|
.host_override("https://your-enterprise-endpoint.com")
|
|
.oauth_config(oauth_config)
|
|
.execute()
|
|
.await?;
|
|
```
|
|
</CodeGroup>
|
|
|
|
For Azure workloads with access to IMDS, use a managed identity instead of a
|
|
client secret:
|
|
|
|
<CodeGroup>
|
|
```python Python icon="python"
|
|
from lancedb.remote import OAuthConfig, OAuthFlowType
|
|
|
|
oauth_config = OAuthConfig(
|
|
issuer_url="https://login.microsoftonline.com/{tenant}/v2.0",
|
|
client_id="your-application-client-id",
|
|
scopes=["api://lancedb-api/.default"],
|
|
flow=OAuthFlowType.AZURE_MANAGED_IDENTITY,
|
|
# Set only for a user-assigned managed identity:
|
|
# managed_identity_client_id="your-user-assigned-identity-client-id",
|
|
)
|
|
```
|
|
|
|
```typescript TypeScript icon="square-js"
|
|
import { OAuthConfig, OAuthFlowType } from "@lancedb/lancedb";
|
|
|
|
const oauthConfig: OAuthConfig = {
|
|
issuerUrl: "https://login.microsoftonline.com/{tenant}/v2.0",
|
|
clientId: "your-application-client-id",
|
|
scopes: ["api://lancedb-api/.default"],
|
|
flow: OAuthFlowType.AzureManagedIdentity,
|
|
// Set only for a user-assigned managed identity:
|
|
// managedIdentityClientId: "your-user-assigned-identity-client-id",
|
|
};
|
|
```
|
|
|
|
```rust Rust icon="rust"
|
|
use lancedb::remote::{OAuthConfig, OAuthFlow};
|
|
|
|
let oauth_config = OAuthConfig {
|
|
issuer_url: "https://login.microsoftonline.com/{tenant}/v2.0".into(),
|
|
client_id: "your-application-client-id".into(),
|
|
client_secret: None,
|
|
scopes: vec!["api://lancedb-api/.default".into()],
|
|
flow: OAuthFlow::AzureManagedIdentity {
|
|
// Set to Some("your-user-assigned-identity-client-id".into())
|
|
// only for a user-assigned managed identity.
|
|
client_id: None,
|
|
},
|
|
client_auth_method: None,
|
|
resource: None,
|
|
audience: None,
|
|
refresh_buffer_secs: None,
|
|
token_cache: None,
|
|
};
|
|
```
|
|
</CodeGroup>
|
|
|
|
`managed_identity_client_id` / `managedIdentityClientId` selects a user-assigned
|
|
identity. Omit it for a system-assigned identity. The required `client_id` /
|
|
`clientId` field does not select the Azure managed identity.
|
|
In Rust, set the `client_id` inside `OAuthFlow::AzureManagedIdentity` to
|
|
`Some(...)` for a user-assigned identity, or `None` for a system-assigned
|
|
identity. The top-level `OAuthConfig::client_id` is the application client ID.
|
|
|
|
For interactive sign-in, configure Authorization Code or Device Code. The
|
|
authorization URL or device verification instructions are written to standard
|
|
error. Authorization Code also tries to open a browser and listens for the
|
|
callback at `http://127.0.0.1:8400/callback` by default. Register that redirect
|
|
URI with your identity provider. Public clients can omit `client_secret`;
|
|
request a refresh token from your provider (often by including
|
|
`offline_access`) if you want to reuse the session.
|
|
|
|
<CodeGroup>
|
|
```python Python icon="python"
|
|
import lancedb
|
|
from lancedb.remote import OAuthConfig, OAuthFlowType, TokenCacheOptions
|
|
|
|
# Use DEVICE_CODE for a CLI without a local browser or callback server.
|
|
oauth_config = OAuthConfig(
|
|
issuer_url="https://your-issuer.example.com",
|
|
client_id="your-public-client-id",
|
|
scopes=["openid", "offline_access", "lancedb.read"],
|
|
flow=OAuthFlowType.AUTHORIZATION_CODE,
|
|
token_cache=TokenCacheOptions(),
|
|
)
|
|
|
|
db = await lancedb.connect_async(
|
|
uri="db://your-database-uri",
|
|
region="us-east-1",
|
|
host_override="https://your-enterprise-endpoint.com",
|
|
oauth_config=oauth_config,
|
|
)
|
|
```
|
|
|
|
```typescript TypeScript icon="square-js"
|
|
import * as lancedb from "@lancedb/lancedb";
|
|
import { OAuthFlowType, type OAuthConfig } from "@lancedb/lancedb";
|
|
|
|
// Use OAuthFlowType.DeviceCode for a CLI without a local browser or callback server.
|
|
const oauthConfig: OAuthConfig = {
|
|
issuerUrl: "https://your-issuer.example.com",
|
|
clientId: "your-public-client-id",
|
|
scopes: ["openid", "offline_access", "lancedb.read"],
|
|
flow: OAuthFlowType.AuthorizationCode,
|
|
tokenCache: {},
|
|
};
|
|
|
|
const db = await lancedb.connect("db://your-database-uri", {
|
|
region: "us-east-1",
|
|
hostOverride: "https://your-enterprise-endpoint.com",
|
|
oauthConfig,
|
|
});
|
|
```
|
|
|
|
```rust Rust icon="rust"
|
|
use lancedb::remote::{AuthorizationCodeOptions, OAuthConfig, OAuthFlow, TokenCacheOptions};
|
|
|
|
// Use OAuthFlow::DeviceCode for a CLI without a local browser or callback server.
|
|
let oauth_config = OAuthConfig {
|
|
issuer_url: "https://your-issuer.example.com".into(),
|
|
client_id: "your-public-client-id".into(),
|
|
client_secret: None,
|
|
scopes: vec![
|
|
"openid".into(),
|
|
"offline_access".into(),
|
|
"lancedb.read".into(),
|
|
],
|
|
flow: OAuthFlow::AuthorizationCode(AuthorizationCodeOptions::new()),
|
|
client_auth_method: None,
|
|
resource: None,
|
|
audience: None,
|
|
refresh_buffer_secs: None,
|
|
token_cache: Some(TokenCacheOptions::new()),
|
|
};
|
|
|
|
let db = lancedb::connect("db://your-database-uri")
|
|
.region("us-east-1")
|
|
.host_override("https://your-enterprise-endpoint.com")
|
|
.oauth_config(oauth_config.clone())
|
|
.execute()
|
|
.await?;
|
|
```
|
|
</CodeGroup>
|
|
|
|
With `DEVICE_CODE` / `DeviceCode` / `OAuthFlow::DeviceCode`, the same
|
|
configuration and connection calls apply; only the `flow` value changes.
|
|
|
|
### Reuse an interactive session {#reuse-an-interactive-session}
|
|
|
|
By default, tokens stay in process memory. Set `token_cache` / `tokenCache`
|
|
for Authorization Code or Device Code to keep refresh tokens across process
|
|
restarts. Only refresh tokens are persisted; access tokens and client secrets
|
|
are not written to the cache. Set `cache_dir` / `cacheDir` to choose the
|
|
directory, or leave it unset to use the platform cache directory. Your
|
|
identity provider must issue a refresh token for a later process to sign in
|
|
without prompting again.
|
|
|
|
Use `OAuthSession` with the same config to log in before connecting, inspect
|
|
whether a refresh token is cached, or remove the local cached credential:
|
|
|
|
<CodeGroup>
|
|
```python Python icon="python"
|
|
from lancedb.remote import OAuthSession
|
|
|
|
session = OAuthSession(oauth_config)
|
|
status = await session.login()
|
|
print(status.refreshable)
|
|
status = await session.status() # Does not contact the provider.
|
|
print(status.refreshable)
|
|
logout = await session.logout()
|
|
print(logout.removed)
|
|
```
|
|
|
|
```typescript TypeScript icon="square-js"
|
|
import { OAuthSession } from "@lancedb/lancedb";
|
|
|
|
const session = new OAuthSession(oauthConfig);
|
|
const status = await session.login();
|
|
console.log(status.refreshable);
|
|
const current = await session.status(); // Does not contact the provider.
|
|
console.log(current.refreshable);
|
|
const logout = await session.logout();
|
|
console.log(logout.removed);
|
|
```
|
|
|
|
```rust Rust icon="rust"
|
|
use lancedb::remote::OAuthSession;
|
|
|
|
let session = OAuthSession::new(oauth_config)?;
|
|
let status = session.login().await?;
|
|
println!("{}", status.refreshable);
|
|
let status = session.status().await?; // Does not contact the provider.
|
|
println!("{}", status.refreshable);
|
|
let logout = session.logout().await?;
|
|
println!("{}", logout.removed);
|
|
```
|
|
</CodeGroup>
|
|
|
|
`login()` runs the interactive flow even when a session is cached. `logout()`
|
|
removes the local cache entry; it does not revoke the provider's token or end
|
|
a browser sign-in. `OAuthSession` requires a persistent cache and supports
|
|
only Authorization Code and Device Code. A cache is unused for Client
|
|
Credentials and rejected for Azure Managed Identity.
|
|
|
|
### Configuration reference {#configuration-reference}
|
|
|
|
The same configuration is available in all three SDKs. Python and Rust use
|
|
`snake_case` field names; TypeScript uses `camelCase`. In Rust, set optional
|
|
`OAuthConfig` fields to `Some(value)` or `None`. Configure `redirect_uri`,
|
|
`callback_port`, and `use_pkce` through the builder methods on
|
|
`AuthorizationCodeOptions`, and select a managed identity through
|
|
`OAuthFlow::AzureManagedIdentity { client_id: ... }`.
|
|
|
|
| Python field / TypeScript field | Required | Description |
|
|
| --- | --- | --- |
|
|
| `issuer_url` / `issuerUrl` | Yes | OIDC issuer URL or OAuth authority URL. For Azure, use `https://login.microsoftonline.com/{tenant_id}/v2.0`. |
|
|
| `client_id` / `clientId` | Yes | Application / client ID registered with your identity provider. |
|
|
| `scopes` | Yes | List of OAuth scopes to request. For Azure managed identity, provide exactly one scope or resource, for example `["api://your-app-id/.default"]`. |
|
|
| `flow` | Yes in Rust; otherwise no | Selects the OAuth flow. Defaults to Client Credentials in Python and TypeScript; Rust requires an explicit `OAuthFlow`. |
|
|
| `client_secret` / `clientSecret` | Conditional | Required for Client Credentials; only required for Authorization Code and Device Code when the provider registers a confidential client. Redacted from the config's `repr` (Python) and `Debug` output (Rust and TypeScript native binding). |
|
|
| `client_auth_method` / `clientAuthMethod` | No | Token endpoint authentication: `ClientAuthMethod.NONE` / `ClientAuthMethod.None` for a public client, `ClientAuthMethod.CLIENT_SECRET_BASIC` / `ClientAuthMethod.ClientSecretBasic`, or `ClientAuthMethod.CLIENT_SECRET_POST` / `ClientAuthMethod.ClientSecretPost`. Defaults to Basic when a client secret is set and no client authentication otherwise. The secret methods require `client_secret` / `clientSecret`. Omit for Azure Managed Identity. |
|
|
| `redirect_uri` / `redirectUri` | No | Authorization Code loopback callback URI. Defaults to `http://127.0.0.1:{callback_port}/callback`; register it with the provider. |
|
|
| `callback_port` / `callbackPort` | No | Authorization Code callback server port (default 8400). If `redirect_uri` / `redirectUri` has an explicit port, the two ports must match. |
|
|
| `use_pkce` / `usePkce` | No | Enable S256 PKCE for Authorization Code (default `true`). |
|
|
| `managed_identity_client_id` / `managedIdentityClientId` | No | Client ID of a user-assigned managed identity. Only used with Azure Managed Identity; omit for system-assigned identities. |
|
|
| `resource` | No | RFC 8707 resource indicator, an absolute URI without a fragment. Sent to authorization and token endpoints, including refresh requests. Not supported for Azure Managed Identity. |
|
|
| `audience` | No | Provider-specific audience sent to authorization and token endpoints, including refresh requests. Not supported for Azure Managed Identity. |
|
|
| `refresh_buffer_secs` / `refreshBufferSecs` | No | How many seconds before token expiry to proactively refresh. Defaults to 300. Keep this well below the token TTL: setting it greater than or equal to the TTL forces a refresh on every request. |
|
|
| `token_cache` / `tokenCache` | No | Opt in to a persistent refresh-token cache for Authorization Code or Device Code. Use `TokenCacheOptions()` in Python, `{}` in TypeScript, or `Some(TokenCacheOptions::new())` in Rust. Defaults to an in-memory session. |
|
|
|
|
`TokenCacheOptions` also accepts `cache_dir` / `cacheDir` to select a cache
|
|
directory and `lock_timeout_secs` / `lockTimeoutSecs` to set the wait for a
|
|
cross-process refresh lock (default 30 seconds).
|
|
In Rust, use the `TokenCacheOptions::cache_dir(...)` and
|
|
`TokenCacheOptions::lock_timeout_secs(...)` builder methods. Token endpoint
|
|
authentication uses `Some(ClientAuthMethod::None)`,
|
|
`Some(ClientAuthMethod::ClientSecretBasic)`, or
|
|
`Some(ClientAuthMethod::ClientSecretPost)`; `None` selects the default.
|
|
|
|
<Warning>
|
|
Treat the client secret like any other production credential. Load it from a
|
|
secret manager or environment variable rather than committing it to source
|
|
control. All three SDKs deliberately omit the secret from their debug/repr output
|
|
so accidental log lines do not expose the value.
|
|
</Warning>
|
|
|
|
Embedded LanceDB has nothing to authenticate to: your process opens the files
|
|
directly, and the object store's own credentials are the only gate.
|