If [OpenID Connect (OIDC)](deploy-configuration-authentication.md) authentication is enabled, its details will be available through the `/v1/.well-known/openid-configuration` endpoint.

If a token is configured, the endpoint redirects to it.

#### Usage

The discovery endpoint accepts a `GET` request:

```js
GET /v1/.well-known/openid-configuration
```

If there is an OIDC provider, the endpoint returns the following fields:

- `href`: The reference to the client.
- `clientId`: The ID of the client.

If there is no OIDC provider, the endpoint returns a `404` HTTP status code.

#### Example

:::code-group{sync="languages"}
```python title="Python"
open_id_configuration = client.get_open_id_configuration()

print(open_id_configuration)
```

```js title="JavaScript/TypeScript"
import weaviate from 'weaviate-client';

const client = await weaviate.connectToLocal()
const response = await client.getOpenIDConfig()

console.log(response);
```

```go title="Go"
package main

import (
  "context"
  "fmt"

  "github.com/weaviate/weaviate-go-client/v5/weaviate"
)

func main() {
  cfg := weaviate.Config{
    Host:   "localhost:8080",
    Scheme: "http",
  }
  client, err := weaviate.NewClient(cfg)
  if err != nil {
    panic(err)
  }

  openIDConfig, err := client.Misc().OpenIDConfigurationGetter().Do(context.Background())
  if err != nil {
    panic(err)
  }
  fmt.Printf("%v", openIDConfig)
}
```

```bash title="Curl"
curl http://localhost:8080/v1/.well-known/openid-configuration
```
:::

If OIDC is configured, the endpoint returns a document like this:

```json
{
  "href": "http://my-token-issuer/auth/realms/my-weaviate-usecase",
  "clientId": "my-weaviate-client"
}
```

## OIDC authentication flows

The OIDC standard allows for many different methods _(flows)_ of obtaining tokens. The appropriate method can vary depending on your situation, including configurations at the token issuer, and your requirements.

Here are some options to consider:

1. Use the `client credentials flow` for machine-to-machine authorization. (Note that this authorizes an app, not a user.)
   - Validated using Okta and Azure as identity providers; GCP does not support client credentials grant flow (as of December 2022).
   - Weaviate's Python client directly supports this method.
   - Client credential flows usually do not come with a refresh token and the credentials are saved in the respective clients to acquire a new access token on expiration of the old one.
2. Use the `resource owner password flow` for trusted applications.
3. Use `hybrid flow` if Azure is your token issuer or if you would like to prevent exposing passwords.

### Support for Weaviate clients

The recommended pattern is to obtain an access token from your IdP using one of the flows above, then pass it to the Weaviate client as a **bearer token**. The client transparently attaches it to every request and, if a refresh token is provided, renews the access token before it expires.

The examples below show how each official client accepts a bearer token. See [Get and pass tokens manually](#get-and-pass-tokens-manually) for an end-to-end example of the token-acquisition step (talking to your IdP), or use your IdP's SDK.

:::code-group{sync="languages"}
```python title="Python"
import os
import weaviate
from weaviate.classes.init import Auth

# Connect to a self-hosted Weaviate instance configured with OIDC.
# Obtain the access token from your identity provider before connecting.
client = weaviate.connect_to_custom(
    http_host="localhost",
    http_port=8580,
    http_secure=False,
    grpc_host="localhost",
    grpc_port=50551,
    grpc_secure=False,
    auth_credentials=Auth.bearer_token(
        access_token=os.environ["WEAVIATE_OIDC_ACCESS_TOKEN"],
        refresh_token=os.environ.get("WEAVIATE_OIDC_REFRESH_TOKEN"),
        expires_in=int(os.environ.get("WEAVIATE_OIDC_EXPIRES_IN", "60")),
    ),
)
```

```typescript title="JavaScript/TypeScript"
// Connect to a self-hosted Weaviate instance configured with OIDC.
// Obtain the access token from your identity provider before connecting.
const client = await weaviate.connectToCustom({
  httpHost: 'localhost',
  httpPort: 8580,
  httpSecure: false,
  grpcHost: 'localhost',
  grpcPort: 50551,
  grpcSecure: false,
  authCredentials: new weaviate.AuthAccessTokenCredentials({
    accessToken: process.env.WEAVIATE_OIDC_ACCESS_TOKEN!,
    refreshToken: process.env.WEAVIATE_OIDC_REFRESH_TOKEN,
    expiresIn: Number(process.env.WEAVIATE_OIDC_EXPIRES_IN ?? 60),
  }),
});
```

```go title="Go"
// Connect to a self-hosted Weaviate instance configured with OIDC.
// Obtain the access token from your identity provider before connecting.
cfg := weaviate.Config{
    Host:   os.Getenv("WEAVIATE_HTTP_HOST"),
    Scheme: "http",
    AuthConfig: auth.BearerToken{
        AccessToken:  os.Getenv("WEAVIATE_OIDC_ACCESS_TOKEN"),
        RefreshToken: os.Getenv("WEAVIATE_OIDC_REFRESH_TOKEN"),
        ExpiresIn:    60,
    },
}
client, err := weaviate.NewClient(cfg)
if err != nil{
    fmt.Println(err)
}
```

```java title="Java"
// Connect to a self-hosted Weaviate instance configured with OIDC.
// Obtain the access token from your identity provider before connecting.
String accessToken = System.getenv("WEAVIATE_OIDC_ACCESS_TOKEN");
String refreshToken = System.getenv("WEAVIATE_OIDC_REFRESH_TOKEN");
long expiresIn = Long.parseLong(
    System.getenv().getOrDefault("WEAVIATE_OIDC_EXPIRES_IN", "60"));

WeaviateClient client = WeaviateClient.connectToCustom(config -> config
    .scheme("http")
    .httpHost("localhost")
    .httpPort(8580)
    .grpcHost("localhost")
    .grpcPort(50551)
    .authentication(Authentication.bearerToken(accessToken, refreshToken, expiresIn)));

System.out.println(client.isReady()); // Should print: `True`

client.close(); // Free up resources
```

```csharp title="C#"
// Connect to a self-hosted Weaviate instance configured with OIDC.
// Obtain the access token from your identity provider before connecting.
var accessToken = Environment.GetEnvironmentVariable("WEAVIATE_OIDC_ACCESS_TOKEN")!;
var refreshToken = Environment.GetEnvironmentVariable("WEAVIATE_OIDC_REFRESH_TOKEN") ?? "";
var expiresIn = int.Parse(Environment.GetEnvironmentVariable("WEAVIATE_OIDC_EXPIRES_IN") ?? "60");

WeaviateClient client = await WeaviateClientBuilder
    .Custom(
        restEndpoint: "localhost",
        restPort: "8580",
        grpcEndpoint: "localhost",
        grpcPort: "50551",
        useSsl: false,
        credentials: Auth.BearerToken(accessToken, expiresIn, refreshToken)
    )
    .BuildAsync();

var isReady = await client.IsReady();
Console.WriteLine(isReady);
```
:::

### Add a Bearer to a Request

When you use an API key to authenticate to Weaviate, add the API key in the request header.

The format is: `Authorization: Bearer WEAVIATE_API_KEY`. Replace `WEAVIATE_API_KEY` with the API key for your Weaviate instance.

For example, the cURL command looks like this:

```bash
curl https://localhost:8080/v1/objects -H "Authorization: Bearer ${WEAVIATE_API_KEY}" | jq
```

### Get and pass tokens manually

:::accordion{title="Manually obtaining and passing tokens"}
For cases or workflows where you may wish to manually obtain a token, we outline below the steps to do so, for the resource owner password flow and hybrid flow.

#### Resource owner password flow

1. Send a GET request to `WEAVIATE_INSTANCE_URL/v1/.well-known/openid-configuration` to fetch Weaviate's OIDC configuration (`wv_oidc_config`). Replace WEAVIATE\_INSTANCE\_URL with your instance URL.
2. Parse the `clientId` and `href` from `wv_oidc_config`.
3. Send a GET request to `href` to fetch the token issuer's OIDC configuration (`token_oidc_config`).
4. If `token_oidc_config` includes the optional `grant_types_supported` key, check that `password` is in the list of values.
   - If `password` is not in the list of values, the token issuer is likely not configured for `resource owner password flow`. You may need to reconfigure the token issuer or use another method.
   - If the `grant_types_supported` key is not available, you may need to contact the token issuer to see if `resource owner password flow` is supported.
5. Send a POST request to the `token_endpoint` of `token_oidc_config` with the body:
   - `{"grant_type": "password", "client_id": client_id, "username": USERNAME, "password": PASSWORD`. Replace `USERNAME` and `PASSWORD` with the actual values.
6. Parse the response (`token_resp`), and look for `access_token` in `token_resp`. This is your Bearer token.

#### Hybrid flow

1. Send a GET request to `WEAVIATE_INSTANCE_URL/v1/.well-known/openid-configuration` to fetch Weaviate's OIDC configuration (`wv_oidc_config`). Replace WEAVIATE\_INSTANCE\_URL with your instance URL.
2. Parse the `clientId` and `href` from `wv_oidc_config`
3. Send a GET request to `href` to fetch the token issuer's OIDC configuration (`token_oidc_config`)
4. Construct a URL (`auth_url`) with the following parameters, based on `authorization_endpoint` from `token_oidc_config`. This will look like the following:
   - `{authorization_endpoint}`?client\_id=`{clientId}`\&response\_type=code%20id\_token\&response\_mode=fragment\&redirect\_url=`{redirect_url}`\&scope=openid\&nonce=abcd
   - the `redirect_url` must have been [pre-registered](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest) with your token issuer.
5. Go to the `auth_url` in your browser, and log in if prompted. If successful, the token issuer will redirect the browser to the `redirect_url`, with additional parameters that include an `id_token` parameter.
6. Parse the `id_token` parameter value. This is your Bearer token.

#### Code example

This example demonstrate how to obtain an OIDC token.

```python
import requests
import re

url = "http://localhost:8080"  # <-- Replace with your actual Weaviate URL

# Get Weaviate's OIDC configuration
weaviate_open_id_config = requests.get(url + "/v1/.well-known/openid-configuration")
if weaviate_open_id_config.status_code == "404":
    print("Your Weaviate instance is not configured with openid")

response_json = weaviate_open_id_config.json()
client_id = response_json["clientId"]
href = response_json["href"]

# Get the token issuer's OIDC configuration
response_auth = requests.get(href)

if "grant_types_supported" in response_auth.json():
    # For resource owner password flow
    assert "password" in response_auth.json()["grant_types_supported"]

    username = "username"  # <-- Replace with the actual username
    password = "password"  # <-- Replace with the actual password

    # Construct the POST request to send to 'token_endpoint'
    auth_body = {
        "grant_type": "password",
        "client_id": client_id,
        "username": username,
        "password": password,
    }
    response_post = requests.post(response_auth.json()["token_endpoint"], auth_body)
    print("Your access_token is:")
    print(response_post.json()["access_token"])
else:
    # For hybrid flow
    authorization_url = response_auth.json()["authorization_endpoint"]
    parameters = {
        "client_id": client_id,
        "response_type": "code%20id_token",
        "response_mode": "fragment",
        "redirect_url": url,
        "scope": "openid",
        "nonce": "abcd",
    }
    # Construct 'auth_url'
    parameter_string = "&".join([key + "=" + item for key, item in parameters.items()])
    response_auth = requests.get(authorization_url + "?" + parameter_string)

    print("To login, open the following url with your browser:")
    print(authorization_url + "?" + parameter_string)
    print(
        "After the login you will be redirected, the token is the 'id_token' parameter of the redirection url."
    )

    # You could use this regular expression to parse the token
    resp_txt = "Redirection URL"
    token = re.search("(?<=id_token=).+(?=&)", resp_txt)[0]

print("Set as bearer token in the clients to access Weaviate.")
```

#### Token lifetime

The token has a configurable expiry time that is set by the token issuer. We suggest establishing a workflow to periodically obtain a new token before expiry.
:::

## Configuring the OIDC token issuer

Configuring the OIDC token issuer is outside the scope of Weaviate's configuration, but here are a few options as a starting point:

- You can use commercial OIDC providers like [Okta](https://www.okta.com/).
- You can run your own OIDC token issuer server. Popular open-source solutions include Java-based [Keycloak](https://www.keycloak.org/) and Golang-based [dex](https://github.com/dexidp/dex).

:::callout{intent="info"}
By default, Weaviate validates that the token includes a specified client id in the audience claim. If your token issuer does not support this feature, you can turn it off as outlined in the [authentication configuration](deploy-configuration-authentication.md#oidc-docker).
:::

## Questions and feedback

Have a question or feedback? Here's how to reach us.

::::card-grid
:::card{title="Community Forum" href="https://forum.weaviate.io/c/support" icon="messages-square"}
Ask questions and connect with other developers on our **Community forum**.
:::

:::card{title="Support" href="/guides/support-overview" icon="life-buoy"}
Weaviate Cloud user or customer? Find the right channel on the **Support page**.
:::
::::

## Related pages

- [Agents](./agents-index.md)
- [AI-assisted Weaviate code generation](./ai-assisted-vibe-coding-index.md)
- [APIs](./apis-index.md)
- [Authorization and authentication](./authorization-and-authentication-index.md)
- [Benchmarks](./benchmarks-index.md)
- [Best practices](./best-practices-index.md)
- [Client libraries](./clients-index.md)
- [Client Libraries / SDKs](./client-libraries-index.md)
- [Cloud](./cloud-index.md)
- [Cloud account management](./cloud-account-management-index.md)

# Agent Instructions

This portal answers questions programmatically. To receive a synthesized,
source-cited answer instead of crawling page by page, append the `?ask=`
query parameter to any page URL on this site:

    /guides/quickstart?ask=how+do+I+authenticate

Optional parameters:

- `&goal=<what-you-are-trying-to-do>` steers the answer toward your
  objective (e.g. `&goal=write+a+python+client`).
- `&version=<label>` scopes the answer to a mounted version when the
  portal publishes more than one.

The response is `text/markdown`: the answer followed by a `# Sources` list
of the portal pages it was grounded in. Status codes are the contract:

- `200` — the answer; `402` — the portal owner’s plan or answer credits are
  exhausted (surface this to your operator; do NOT retry); `429` — you are
  rate-limited; back off for the `Retry-After` seconds; `503` — the answer
  lane is temporarily unavailable; fall back to crawling the `.md` pages.

For the full corpus map read `llms.txt` at the site root; for the tool
surface (search + page fetch as MCP tools) see `/mcp`.
