diff --git a/docs/sphinx/source/_static/add_token.png b/docs/sphinx/source/_static/add_token.png
new file mode 100644
index 00000000..cbf15751
Binary files /dev/null and b/docs/sphinx/source/_static/add_token.png differ
diff --git a/docs/sphinx/source/authenticating-to-vespa-cloud.ipynb b/docs/sphinx/source/authenticating-to-vespa-cloud.ipynb
new file mode 100644
index 00000000..d9cb95ee
--- /dev/null
+++ b/docs/sphinx/source/authenticating-to-vespa-cloud.ipynb
@@ -0,0 +1,984 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "given-adoption",
+ "metadata": {
+ "pycharm": {
+ "name": "#%% md\n"
+ }
+ },
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ "\n",
+ "# Authenticating to Vespa Cloud\n",
+ "\n",
+ "Security is a top priority for the Vespa Team.\n",
+ "We understand that as a newcomer to Vespa, the different authentication methods may not always be immediately clear.\n",
+ "\n",
+ "This notebook is intended to provide some clarity on the different authentication methods needed when interacting with Vespa Cloud for different purposes.\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4f8c1448",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " Refer to
troubleshooting \n",
+ " for any problem when running this guide.\n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "148d275b",
+ "metadata": {},
+ "source": [
+ "**Pre-requisite**: Create a tenant at [cloud.vespa.ai](https://cloud.vespa.ai/), save the tenant name.\n",
+ "\n",
+ "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/vespa-engine/pyvespa/blob/master/docs/sphinx/source/authenticating-to-vespa-cloud.ipynb)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "366b0d83",
+ "metadata": {},
+ "source": [
+ "## Install\n",
+ "\n",
+ "Install [pyvespa](https://pyvespa.readthedocs.io/) >= 0.45\n",
+ "and the [Vespa CLI](https://docs.vespa.ai/en/vespa-cli.html).\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "136750de",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Requirement already satisfied: pyvespa in /Users/thomas/.pyenv/versions/3.9.19/envs/pyvespa-dev/lib/python3.9/site-packages (0.45.0)\n",
+ "Requirement already satisfied: vespacli in /Users/thomas/.pyenv/versions/3.9.19/envs/pyvespa-dev/lib/python3.9/site-packages (8.371.16)\n",
+ "Requirement already satisfied: cryptography in /Users/thomas/.pyenv/versions/3.9.19/envs/pyvespa-dev/lib/python3.9/site-packages (from pyvespa) (43.0.0)\n",
+ "Requirement already satisfied: requests-toolbelt in /Users/thomas/.pyenv/versions/3.9.19/envs/pyvespa-dev/lib/python3.9/site-packages (from pyvespa) (1.0.0)\n",
+ "Requirement already satisfied: docker in /Users/thomas/.pyenv/versions/3.9.19/envs/pyvespa-dev/lib/python3.9/site-packages (from pyvespa) (7.1.0)\n",
+ "Requirement already satisfied: aiohttp in /Users/thomas/.pyenv/versions/3.9.19/envs/pyvespa-dev/lib/python3.9/site-packages (from pyvespa) (3.10.1)\n",
+ "Requirement already satisfied: requests==2.31 in /Users/thomas/.pyenv/versions/3.9.19/envs/pyvespa-dev/lib/python3.9/site-packages (from pyvespa) (2.31.0)\n",
+ "Requirement already satisfied: tenacity>=8.4.1 in /Users/thomas/.pyenv/versions/3.9.19/envs/pyvespa-dev/lib/python3.9/site-packages (from pyvespa) (9.0.0)\n",
+ "Requirement already satisfied: typing-extensions in /Users/thomas/.pyenv/versions/3.9.19/envs/pyvespa-dev/lib/python3.9/site-packages (from pyvespa) (4.12.2)\n",
+ "Requirement already satisfied: python-dateutil in /Users/thomas/.pyenv/versions/3.9.19/envs/pyvespa-dev/lib/python3.9/site-packages (from pyvespa) (2.9.0.post0)\n",
+ "Requirement already satisfied: jinja2 in /Users/thomas/.pyenv/versions/3.9.19/envs/pyvespa-dev/lib/python3.9/site-packages (from pyvespa) (3.1.4)\n",
+ "Requirement already satisfied: certifi>=2017.4.17 in /Users/thomas/.pyenv/versions/3.9.19/envs/pyvespa-dev/lib/python3.9/site-packages (from requests==2.31->pyvespa) (2024.7.4)\n",
+ "Requirement already satisfied: urllib3<3,>=1.21.1 in /Users/thomas/.pyenv/versions/3.9.19/envs/pyvespa-dev/lib/python3.9/site-packages (from requests==2.31->pyvespa) (2.2.2)\n",
+ "Requirement already satisfied: idna<4,>=2.5 in /Users/thomas/.pyenv/versions/3.9.19/envs/pyvespa-dev/lib/python3.9/site-packages (from requests==2.31->pyvespa) (3.7)\n",
+ "Requirement already satisfied: charset-normalizer<4,>=2 in /Users/thomas/.pyenv/versions/3.9.19/envs/pyvespa-dev/lib/python3.9/site-packages (from requests==2.31->pyvespa) (3.3.2)\n",
+ "Requirement already satisfied: frozenlist>=1.1.1 in /Users/thomas/.pyenv/versions/3.9.19/envs/pyvespa-dev/lib/python3.9/site-packages (from aiohttp->pyvespa) (1.4.1)\n",
+ "Requirement already satisfied: yarl<2.0,>=1.0 in /Users/thomas/.pyenv/versions/3.9.19/envs/pyvespa-dev/lib/python3.9/site-packages (from aiohttp->pyvespa) (1.9.4)\n",
+ "Requirement already satisfied: attrs>=17.3.0 in /Users/thomas/.pyenv/versions/3.9.19/envs/pyvespa-dev/lib/python3.9/site-packages (from aiohttp->pyvespa) (24.1.0)\n",
+ "Requirement already satisfied: aiosignal>=1.1.2 in /Users/thomas/.pyenv/versions/3.9.19/envs/pyvespa-dev/lib/python3.9/site-packages (from aiohttp->pyvespa) (1.3.1)\n",
+ "Requirement already satisfied: multidict<7.0,>=4.5 in /Users/thomas/.pyenv/versions/3.9.19/envs/pyvespa-dev/lib/python3.9/site-packages (from aiohttp->pyvespa) (6.0.5)\n",
+ "Requirement already satisfied: async-timeout<5.0,>=4.0 in /Users/thomas/.pyenv/versions/3.9.19/envs/pyvespa-dev/lib/python3.9/site-packages (from aiohttp->pyvespa) (4.0.3)\n",
+ "Requirement already satisfied: aiohappyeyeballs>=2.3.0 in /Users/thomas/.pyenv/versions/3.9.19/envs/pyvespa-dev/lib/python3.9/site-packages (from aiohttp->pyvespa) (2.3.4)\n",
+ "Requirement already satisfied: cffi>=1.12 in /Users/thomas/.pyenv/versions/3.9.19/envs/pyvespa-dev/lib/python3.9/site-packages (from cryptography->pyvespa) (1.16.0)\n",
+ "Requirement already satisfied: MarkupSafe>=2.0 in /Users/thomas/.pyenv/versions/3.9.19/envs/pyvespa-dev/lib/python3.9/site-packages (from jinja2->pyvespa) (2.1.5)\n",
+ "Requirement already satisfied: six>=1.5 in /Users/thomas/.pyenv/versions/3.9.19/envs/pyvespa-dev/lib/python3.9/site-packages (from python-dateutil->pyvespa) (1.16.0)\n",
+ "Requirement already satisfied: pycparser in /Users/thomas/.pyenv/versions/3.9.19/envs/pyvespa-dev/lib/python3.9/site-packages (from cffi>=1.12->cryptography->pyvespa) (2.22)\n",
+ "\n",
+ "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.0.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.2\u001b[0m\n",
+ "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n"
+ ]
+ }
+ ],
+ "source": [
+ "!pip3 install pyvespa vespacli"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0229ff0e",
+ "metadata": {},
+ "source": [
+ "For background context, it is useful to read the [Vespa Cloud Security Guide](https://cloud.vespa.ai/en/security/guide).\n",
+ "\n",
+ "## Control-plane vs Data-plane\n",
+ "\n",
+ "This may be self-explanatory for some, but it is worth mentioning that Vespa Cloud has two main components: the control-plane and the data-plane, which provide access to different functionalities.\n",
+ "\n",
+ "| | Control-plane | Data-plane | Comments |\n",
+ "| ------------------------------------------------------------------------------------------ | ------------- | ---------- | ------------------------------------------------------------------------------------------ |\n",
+ "| Deploy application | ✅ | ❌ | |\n",
+ "| Modify application (re-deploy) | ✅ | ❌ | |\n",
+ "| Add or modify data-plane certs or token(s) | ✅ | ❌ | |\n",
+ "| Feed data | ❌ | ✅ | |\n",
+ "| Query data | ❌ | ✅ | |\n",
+ "| Delete data | ❌ | ✅ | |\n",
+ "| [Visiting](https://docs.vespa.ai/en/visiting.html) | ❌ | ✅ | |\n",
+ "| [Monitoring](https://cloud.vespa.ai/en/monitoring) | ❌ | ✅ | |\n",
+ "| Get application package | ✅ | ❌ | |\n",
+ "| [vespa auth login](https://docs.vespa.ai/en/reference/vespa-cli/vespa_auth_login.html) | ✅ | ❌ | Interactive control-plane login in browser |\n",
+ "| [vespa auth api-key](https://docs.vespa.ai/en/reference/vespa-cli/vespa_auth_api-key.html) | ✅ | ❌ | Headless control-plane authentication with an API key generated in the Vespa Cloud console |\n",
+ "| [vespa auth cert](https://docs.vespa.ai/en/reference/vespa-cli/vespa_auth_cert.html) | ❌ | ✅ | Used to generate a certificate for a data-plane connection |\n",
+ "| [VespaCloud](https://pyvespa.readthedocs.io/en/latest/reference-api.html#vespacloud) | ✅ | ❌ | `VespaCloud` is a control-plane connection to Vespa Cloud |\n",
+ "| [VespaDocker](https://pyvespa.readthedocs.io/en/latest/reference-api.html#vespadocker) | ✅ | ❌ | `VespaDocker` is a control-plane connection to a Vespa server running in Docker |\n",
+ "| [Vespa](https://pyvespa.readthedocs.io/en/latest/reference-api.html#vespa) | ❌ | ✅ | `Vespa` is a data-plane connection to an existing Vespa application |\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "301360d5",
+ "metadata": {},
+ "source": [
+ "## Defining your application\n",
+ "\n",
+ "To initialize a connection to Vespa Cloud, you need to define your tenant name and application name.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "9ca4da83",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Replace with your tenant name from the Vespa Cloud Console\n",
+ "tenant_name = \"vespa-team\"\n",
+ "# Replace with your application name (does not need to exist yet)\n",
+ "application = \"authdemo\""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bfc6b343",
+ "metadata": {},
+ "source": [
+ "## Defining your application package\n",
+ "\n",
+ "An [application package](https://docs.vespa.ai/en/application-packages.html) is the whole Vespa application configuration.\n",
+ "It can either be constructed directly from python (as we will do below) or initalized from a path, for example by cloning a sample application from the [Vespa sample apps](https://github.com/vespa-engine/sample-apps).\n",
+ "\n",
+ "\n",
+ "\n",
+ "For this guide, we will create a minimal application package. See other guides for more complex examples.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "c405f35c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from vespa.package import ApplicationPackage, Field, Schema, Document\n",
+ "\n",
+ "schema_name = \"doc\"\n",
+ "\n",
+ "schema = Schema(\n",
+ " name=schema_name,\n",
+ " document=Document(\n",
+ " fields=[\n",
+ " Field(name=\"id\", type=\"string\", indexing=[\"summary\"]),\n",
+ " Field(\n",
+ " name=\"title\",\n",
+ " type=\"string\",\n",
+ " indexing=[\"index\", \"summary\"],\n",
+ " index=\"enable-bm25\",\n",
+ " ),\n",
+ " Field(\n",
+ " name=\"body\",\n",
+ " type=\"string\",\n",
+ " indexing=[\"index\", \"summary\"],\n",
+ " index=\"enable-bm25\",\n",
+ " ),\n",
+ " ]\n",
+ " ),\n",
+ ")\n",
+ "\n",
+ "package = ApplicationPackage(name=application, schema=[schema])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "03d2c531",
+ "metadata": {},
+ "source": [
+ "## Control-plane authentication\n",
+ "\n",
+ "Next, we need to authenticate to the Vespa Cloud control-plane.\n",
+ "There are two ways to authenticate to the control-plane:\n",
+ "\n",
+ "### 1. **Interactive login**:\n",
+ "\n",
+ "This is the recommended way to authenticate to the control-plane. It opens a browser window for you to authenticate with either google or github.\n",
+ "\n",
+ "This method does not work on windows, currently. You can run `vespa auth login` in a terminal to authenticate first, and then use this method (which will then reuse the generated token).\n",
+ "\n",
+ "(We will not run this method here, as the notebook is run in CI, but you should run it in your local environment)\n",
+ "\n",
+ "```python\n",
+ "from vespa.deployment import VespaCloud\n",
+ "\n",
+ "vespa_cloud = VespaCloud(\n",
+ " tenant=tenant_name,\n",
+ " application=application,\n",
+ " application_package=package, # Could also initialize from application_root (path to application package)\n",
+ ")\n",
+ "```\n",
+ "\n",
+ "You should see something similar to this:\n",
+ "\n",
+ "```log\n",
+ "Checking for access token in auth.json...\n",
+ "Access token expired. Please re-authenticate.\n",
+ "Your Device Confirmation code is: DRDT-ZZDC\n",
+ "Automatically open confirmation page in your default browser? [Y/n] y\n",
+ "Opened link in your browser: https://vespa.auth0.com/activate?user_code=DRDT-ZZDC\n",
+ "Waiting for login to complete in browser ... done;1m⣯\n",
+ "Success: Logged in\n",
+ " auth.json created at /Users/thomas/.vespa/auth.json\n",
+ "Successfully obtained access token for control plane access.\n",
+ "```\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "63f1dd3d",
+ "metadata": {},
+ "source": [
+ "### 2. **API-key authentication**\n",
+ "\n",
+ "This is a headless way to authenticate to the control-plane.\n",
+ "\n",
+ "Note that the key must be generated, either with `vespa auth api-key` or in the Vespa Cloud console directly.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "136b884e",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Setting application...\n",
+ "Running: vespa config set application vespa-team.authdemo\n",
+ "Setting target cloud...\n",
+ "Running: vespa config set target cloud\n",
+ "\n",
+ "Api-key found for control plane access. Using api-key.\n"
+ ]
+ }
+ ],
+ "source": [
+ "from vespa.deployment import VespaCloud\n",
+ "from vespa.application import Vespa\n",
+ "import os\n",
+ "\n",
+ "# Key is only used for CI/CD. Can be removed if logging in interactively\n",
+ "key = os.getenv(\"VESPA_TEAM_API_KEY\", None)\n",
+ "if key is not None:\n",
+ " key = key.replace(r\"\\n\", \"\\n\") # To parse key correctly\n",
+ "\n",
+ "\n",
+ "vespa_cloud = VespaCloud(\n",
+ " tenant=tenant_name, # Note that the name cannot contain the characters `-` or `_`.\n",
+ " application=application,\n",
+ " key_content=key, # Prefer to use key_location=\"\"\n",
+ " application_package=package,\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "dec50045",
+ "metadata": {},
+ "source": [
+ "When you have authenticated to the control-plane of Vespa Cloud, key/cert for data-plane authentication will be generated automatically for you, if none exists.\n",
+ "\n",
+ "The `data-plane-public-cert.pem` will be added to the application package (in `/security/clients.pem` directory) that will be deployed. You should keep them safe, as any app or users that need data-plane access to your Vespa application will need them.\n",
+ "\n",
+ "For `dev`-deployments, we allow redeploying an application with a different key/cert than the previous deployment. For `prod`-deployments however, this is not allowed, and will require a `validation-overrides`-specification in the application package.\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "careful-savage",
+ "metadata": {},
+ "source": [
+ "## Deploy to Vespa Cloud\n",
+ "\n",
+ "The app is now defined and ready to deploy to Vespa Cloud.\n",
+ "\n",
+ "Deploy `package` to Vespa Cloud, by creating an instance of\n",
+ "[VespaCloud](https://pyvespa.readthedocs.io/en/latest/reference-api.html#vespa.deployment.VespaCloud):\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "197c0a27",
+ "metadata": {},
+ "source": [
+ "The following will upload the application package to Vespa Cloud Dev Zone (`aws-us-east-1c`), read more about [Vespa Zones](https://cloud.vespa.ai/en/reference/zones.html).\n",
+ "The Vespa Cloud Dev Zone is considered as a sandbox environment where resources are down-scaled and idle deployments are expired automatically.\n",
+ "For information about production deployments, see the following [docs](https://cloud.vespa.ai/en/reference/deployment).\n",
+ "\n",
+ "> Note: Deployments to dev and perf expire after 14 days of inactivity, i.e., 14 days after running deploy. This applies to all plans, not only the Free Trial. Use the Vespa Console to extend the expiry period, or redeploy the application to add 14 more days.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "337d9b05",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Deployment started in run 1 of dev-aws-us-east-1c for vespa-team.authdemo. This may take a few minutes the first time.\n",
+ "INFO [12:23:44] Deploying platform version 8.395.28 and application dev build 1 for dev-aws-us-east-1c of default ...\n",
+ "INFO [12:23:44] Using CA signed certificate version 1\n",
+ "INFO [12:23:44] Using 1 nodes in container cluster 'authdemo_container'\n",
+ "INFO [12:23:50] Session 304526 for tenant 'vespa-team' prepared and activated.\n",
+ "INFO [12:24:10] ######## Details for all nodes ########\n",
+ "INFO [12:24:16] h93726a.dev.aws-us-east-1c.vespa-external.aws.oath.cloud: expected to be UP\n",
+ "INFO [12:24:16] --- platform vespa/cloud-tenant-rhel8:8.395.28\n",
+ "INFO [12:24:16] --- storagenode on port 19102 has not started \n",
+ "INFO [12:24:16] --- searchnode on port 19107 has not started \n",
+ "INFO [12:24:16] --- distributor on port 19111 has not started \n",
+ "INFO [12:24:16] --- metricsproxy-container on port 19092 has not started \n",
+ "INFO [12:24:16] h93272b.dev.aws-us-east-1c.vespa-external.aws.oath.cloud: expected to be UP\n",
+ "INFO [12:24:16] --- platform vespa/cloud-tenant-rhel8:8.395.28\n",
+ "INFO [12:24:16] --- container-clustercontroller on port 19050 has not started \n",
+ "INFO [12:24:16] --- metricsproxy-container on port 19092 has not started \n",
+ "INFO [12:24:16] h93394a.dev.aws-us-east-1c.vespa-external.aws.oath.cloud: expected to be UP\n",
+ "INFO [12:24:16] --- platform vespa/cloud-tenant-rhel8:8.395.28\n",
+ "INFO [12:24:16] --- logserver-container on port 4080 has not started \n",
+ "INFO [12:24:16] --- metricsproxy-container on port 19092 has not started \n",
+ "INFO [12:24:16] h96124a.dev.aws-us-east-1c.vespa-external.aws.oath.cloud: expected to be UP\n",
+ "INFO [12:24:16] --- platform vespa/cloud-tenant-rhel8:8.395.28\n",
+ "INFO [12:24:16] --- container on port 4080 has not started \n",
+ "INFO [12:24:16] --- metricsproxy-container on port 19092 has not started \n",
+ "INFO [12:25:02] Found endpoints:\n",
+ "INFO [12:25:02] - dev.aws-us-east-1c\n",
+ "INFO [12:25:02] |-- https://b0502030.a13b2ab6.z.vespa-app.cloud/ (cluster 'authdemo_container')\n",
+ "INFO [12:25:03] Deployment complete!\n",
+ "Found mtls endpoint for authdemo_container\n",
+ "URL: https://b0502030.a13b2ab6.z.vespa-app.cloud/\n",
+ "Connecting to https://b0502030.a13b2ab6.z.vespa-app.cloud/\n",
+ "Using mtls_key_cert Authentication against endpoint https://b0502030.a13b2ab6.z.vespa-app.cloud//ApplicationStatus\n",
+ "Application is up!\n",
+ "Finished deployment.\n"
+ ]
+ }
+ ],
+ "source": [
+ "app: Vespa = vespa_cloud.deploy()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "aaae2f91",
+ "metadata": {},
+ "source": [
+ "If the deployment failed, it is possible you forgot to add the key in the Vespa Cloud Console in the `vespa auth api-key` step above.\n",
+ "\n",
+ "If you can authenticate, you should see lines like the following\n",
+ "\n",
+ "```\n",
+ " Deployment started in run 1 of dev-aws-us-east-1c for mytenant.authdemo.\n",
+ "```\n",
+ "\n",
+ "The deployment takes a few minutes the first time while Vespa Cloud sets up the resources for your Vespa application\n",
+ "\n",
+ "`app` now holds a reference to a [Vespa](https://pyvespa.readthedocs.io/en/latest/reference-api.html#vespa.application.Vespa) instance. We can access the\n",
+ "mTLS protected endpoint name using the control-plane (vespa_cloud) instance. This endpoint we can query and feed to (data plane access) using the\n",
+ "mTLS certificate generated in previous steps.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "98ff13f6",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Found mtls endpoint for authdemo_container\n",
+ "URL: https://b0502030.a13b2ab6.z.vespa-app.cloud/\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "'https://b0502030.a13b2ab6.z.vespa-app.cloud/'"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "mtls_endpoint = vespa_cloud.get_mtls_endpoint()\n",
+ "mtls_endpoint"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6fa8a717",
+ "metadata": {},
+ "source": [
+ "## Data-plane authentication\n",
+ "\n",
+ "As we have mentioned, there are two ways to authenticate to the data-plane:\n",
+ "\n",
+ "### 1. **mTLS - Certificate authentication**\n",
+ "\n",
+ "This is the default way to authenticate to the data-plane. It uses the certificate which was added to the application package upon deployment.\n",
+ "\n",
+ "### 2. **Token-based authentication**\n",
+ "\n",
+ "A more convenient way to authenticate to the data-plane is to use a token. A token must be generated in the Vespa Cloud console.\n",
+ "For more details, see the [Security Guide](https://cloud.vespa.ai/en/security/guide#configure-tokens)\n",
+ "\n",
+ "![add token](_static/add_token.png)\n",
+ "\n",
+ "Set a reasonable expiry, and copy the token to a safe place, such as for instance a passwordmanager. You will not be able to see it again.\n",
+ "\n",
+ "After the token is generated, you need to add it as an auth-client to the application you want to access.\n",
+ "\n",
+ "In pyvespa, this is done by adding the AuthClients to the application package:\n",
+ "\n",
+ "**NB! - The method below applies to `dev`**\n",
+ "\n",
+ "The approach described above applies to `dev`-deployments. For `prod`-deployments, it is a little more complex, and you need to add the `AuthClients` to your application package like this:\n",
+ "\n",
+ "```python\n",
+ "from vespa.package import ContainerCluster\n",
+ "\n",
+ "auth_clients = [\n",
+ " AuthClient(\n",
+ " id=\"mtls\",\n",
+ " permissions=[\"read\"],\n",
+ " parameters=[Parameter(\"certificate\", {\"file\": \"security/clients.pem\"})],\n",
+ " ),\n",
+ " AuthClient(\n",
+ " id=\"token\",\n",
+ " permissions=[\"read\"], # Set the permissions you need\n",
+ " parameters=[Parameter(\"token\", {\"id\": CLIENT_TOKEN_ID})],\n",
+ " ),\n",
+ " ]\n",
+ "# Add prod deployment config\n",
+ "prod_region = \"aws-us-east-1c\"\n",
+ "clusters = [\n",
+ " ContentCluster(\n",
+ " id=f\"{schema_name}_content\",\n",
+ " nodes=Nodes(count=\"2\"),\n",
+ " document_name=schema_name,\n",
+ " min_redundancy=\"2\",\n",
+ " ),\n",
+ " ContainerCluster(\n",
+ " id=f\"{schema_name}_container\",\n",
+ " nodes=Nodes(count=\"2\"),\n",
+ " auth_clients=auth_clients, # Note that the auth_clients are added here for prod deployments\n",
+ " ),\n",
+ "]\n",
+ "prod_region = \"aws-us-east-1c\"\n",
+ "deployment_config = DeploymentConfiguration(\n",
+ " environment=\"prod\", regions=[prod_region]\n",
+ ")\n",
+ "app_package = ApplicationPackage(name=application, schema=[schema], clusters=clusters, deployment=deployment_config)\n",
+ "```\n",
+ "\n",
+ "See [Application Package reference](https://cloud.vespa.ai/en/reference/application-package) for more details.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "1934d87c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from vespa.package import AuthClient, Parameter\n",
+ "\n",
+ "CLIENT_TOKEN_ID = \"pyvespa_integration\" # os.environ.get(\"VESPA_CLIENT_TOKEN_ID\")\n",
+ "# Same as token name from the Vespa Cloud Console\n",
+ "auth_clients = [\n",
+ " AuthClient(\n",
+ " id=\"mtls\", # Note that you still need to include the mtls client.\n",
+ " permissions=[\"read\", \"write\"],\n",
+ " parameters=[Parameter(\"certificate\", {\"file\": \"security/clients.pem\"})],\n",
+ " ),\n",
+ " AuthClient(\n",
+ " id=\"token\",\n",
+ " permissions=[\"read\"],\n",
+ " parameters=[Parameter(\"token\", {\"id\": CLIENT_TOKEN_ID})],\n",
+ " ),\n",
+ "]\n",
+ "\n",
+ "app_package = ApplicationPackage(\n",
+ " name=application, schema=[schema], auth_clients=auth_clients\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2c36dfb9",
+ "metadata": {},
+ "source": [
+ "Notice that we added the `read` and `write` permissions to mtls clients, and only `read` to the token client.\n",
+ "\n",
+ "Make sure to restrict the permissions to suit your needs.\n",
+ "\n",
+ "Now, we can redeploy the application package with the new auth-client added:\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "9e7bdcc5",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Setting application...\n",
+ "Running: vespa config set application vespa-team.authdemo\n",
+ "Setting target cloud...\n",
+ "Running: vespa config set target cloud\n",
+ "\n",
+ "Api-key found for control plane access. Using api-key.\n",
+ "Deployment started in run 2 of dev-aws-us-east-1c for vespa-team.authdemo. This may take a few minutes the first time.\n",
+ "INFO [12:25:08] Deploying platform version 8.395.28 and application dev build 2 for dev-aws-us-east-1c of default ...\n",
+ "INFO [12:25:08] Using CA signed certificate version 1\n",
+ "INFO [12:25:09] Using 1 nodes in container cluster 'authdemo_container'\n",
+ "INFO [12:25:12] Session 304527 for tenant 'vespa-team' prepared and activated.\n",
+ "INFO [12:25:12] ######## Details for all nodes ########\n",
+ "INFO [12:25:12] h93726a.dev.aws-us-east-1c.vespa-external.aws.oath.cloud: expected to be UP\n",
+ "INFO [12:25:12] --- platform vespa/cloud-tenant-rhel8:8.395.28\n",
+ "INFO [12:25:12] --- storagenode on port 19102 has config generation 304526, wanted is 304527\n",
+ "INFO [12:25:12] --- searchnode on port 19107 has config generation 304527, wanted is 304527\n",
+ "INFO [12:25:12] --- distributor on port 19111 has config generation 304527, wanted is 304527\n",
+ "INFO [12:25:12] --- metricsproxy-container on port 19092 has config generation 304526, wanted is 304527\n",
+ "INFO [12:25:12] h93272b.dev.aws-us-east-1c.vespa-external.aws.oath.cloud: expected to be UP\n",
+ "INFO [12:25:12] --- platform vespa/cloud-tenant-rhel8:8.395.28\n",
+ "INFO [12:25:12] --- container-clustercontroller on port 19050 has config generation 304527, wanted is 304527\n",
+ "INFO [12:25:12] --- metricsproxy-container on port 19092 has config generation 304527, wanted is 304527\n",
+ "INFO [12:25:12] h93394a.dev.aws-us-east-1c.vespa-external.aws.oath.cloud: expected to be UP\n",
+ "INFO [12:25:12] --- platform vespa/cloud-tenant-rhel8:8.395.28\n",
+ "INFO [12:25:12] --- logserver-container on port 4080 has config generation 304527, wanted is 304527\n",
+ "INFO [12:25:12] --- metricsproxy-container on port 19092 has config generation 304527, wanted is 304527\n",
+ "INFO [12:25:12] h96124a.dev.aws-us-east-1c.vespa-external.aws.oath.cloud: expected to be UP\n",
+ "INFO [12:25:12] --- platform vespa/cloud-tenant-rhel8:8.395.28\n",
+ "INFO [12:25:12] --- container on port 4080 has config generation 304526, wanted is 304527\n",
+ "INFO [12:25:12] --- metricsproxy-container on port 19092 has config generation 304527, wanted is 304527\n",
+ "INFO [12:25:23] Found endpoints:\n",
+ "INFO [12:25:23] - dev.aws-us-east-1c\n",
+ "INFO [12:25:23] |-- https://b0502030.a13b2ab6.z.vespa-app.cloud/ (cluster 'authdemo_container')\n",
+ "INFO [12:25:53] Unhealthy targets: Initial health checks in progress: 1, Target deregistration is in progress: 1\n",
+ "INFO [12:25:53] Found endpoints:\n",
+ "INFO [12:25:53] - dev.aws-us-east-1c\n",
+ "INFO [12:25:53] |-- https://b0502030.a13b2ab6.z.vespa-app.cloud/ (cluster 'authdemo_container')\n",
+ "INFO [12:26:18] Unhealthy targets: Initial health checks in progress: 1, Target deregistration is in progress: 1\n",
+ "INFO [12:26:22] Found endpoints:\n",
+ "INFO [12:26:22] - dev.aws-us-east-1c\n",
+ "INFO [12:26:22] |-- https://b0502030.a13b2ab6.z.vespa-app.cloud/ (cluster 'authdemo_container')\n",
+ "INFO [12:26:22] Unhealthy targets: Initial health checks in progress: 1, Target deregistration is in progress: 1\n",
+ "INFO [12:26:32] Found endpoints:\n",
+ "INFO [12:26:32] - dev.aws-us-east-1c\n",
+ "INFO [12:26:32] |-- https://b0502030.a13b2ab6.z.vespa-app.cloud/ (cluster 'authdemo_container')\n",
+ "INFO [12:26:32] Unhealthy targets: Initial health checks in progress: 1, Target deregistration is in progress: 1\n",
+ "INFO [12:26:42] Found endpoints:\n",
+ "INFO [12:26:42] - dev.aws-us-east-1c\n",
+ "INFO [12:26:42] |-- https://b0502030.a13b2ab6.z.vespa-app.cloud/ (cluster 'authdemo_container')\n",
+ "INFO [12:26:42] Unhealthy targets: Initial health checks in progress: 1, Target deregistration is in progress: 1\n",
+ "INFO [12:26:52] Found endpoints:\n",
+ "INFO [12:26:52] - dev.aws-us-east-1c\n",
+ "INFO [12:26:52] |-- https://b0502030.a13b2ab6.z.vespa-app.cloud/ (cluster 'authdemo_container')\n",
+ "INFO [12:26:52] Unhealthy targets: Target deregistration is in progress: 1\n",
+ "INFO [12:27:02] Found endpoints:\n",
+ "INFO [12:27:02] - dev.aws-us-east-1c\n",
+ "INFO [12:27:02] |-- https://b0502030.a13b2ab6.z.vespa-app.cloud/ (cluster 'authdemo_container')\n",
+ "INFO [12:27:02] Unhealthy targets: Target deregistration is in progress: 1\n",
+ "INFO [12:27:12] Found endpoints:\n",
+ "INFO [12:27:12] - dev.aws-us-east-1c\n",
+ "INFO [12:27:12] |-- https://b0502030.a13b2ab6.z.vespa-app.cloud/ (cluster 'authdemo_container')\n",
+ "INFO [12:27:12] Unhealthy targets: Target deregistration is in progress: 1\n",
+ "INFO [12:27:22] Found endpoints:\n",
+ "INFO [12:27:22] - dev.aws-us-east-1c\n",
+ "INFO [12:27:22] |-- https://b0502030.a13b2ab6.z.vespa-app.cloud/ (cluster 'authdemo_container')\n",
+ "INFO [12:27:23] Unhealthy targets: Target deregistration is in progress: 1\n",
+ "INFO [12:27:32] Found endpoints:\n",
+ "INFO [12:27:32] - dev.aws-us-east-1c\n",
+ "INFO [12:27:32] |-- https://b0502030.a13b2ab6.z.vespa-app.cloud/ (cluster 'authdemo_container')\n",
+ "INFO [12:27:33] Unhealthy targets: Target deregistration is in progress: 1\n",
+ "INFO [12:27:42] Found endpoints:\n",
+ "INFO [12:27:42] - dev.aws-us-east-1c\n",
+ "INFO [12:27:42] |-- https://b0502030.a13b2ab6.z.vespa-app.cloud/ (cluster 'authdemo_container')\n",
+ "INFO [12:27:42] Unhealthy targets: Target deregistration is in progress: 1\n",
+ "INFO [12:27:53] Found endpoints:\n",
+ "INFO [12:27:53] - dev.aws-us-east-1c\n",
+ "INFO [12:27:53] |-- https://b0502030.a13b2ab6.z.vespa-app.cloud/ (cluster 'authdemo_container')\n",
+ "INFO [12:27:53] Unhealthy targets: Target deregistration is in progress: 1\n",
+ "INFO [12:28:02] Found endpoints:\n",
+ "INFO [12:28:02] - dev.aws-us-east-1c\n",
+ "INFO [12:28:02] |-- https://b0502030.a13b2ab6.z.vespa-app.cloud/ (cluster 'authdemo_container')\n",
+ "INFO [12:28:02] Unhealthy targets: Target deregistration is in progress: 1\n",
+ "INFO [12:28:12] Found endpoints:\n",
+ "INFO [12:28:12] - dev.aws-us-east-1c\n",
+ "INFO [12:28:12] |-- https://b0502030.a13b2ab6.z.vespa-app.cloud/ (cluster 'authdemo_container')\n",
+ "INFO [12:28:12] Unhealthy targets: Target deregistration is in progress: 1\n",
+ "INFO [12:28:23] Found endpoints:\n",
+ "INFO [12:28:23] - dev.aws-us-east-1c\n",
+ "INFO [12:28:23] |-- https://b0502030.a13b2ab6.z.vespa-app.cloud/ (cluster 'authdemo_container')\n",
+ "INFO [12:28:23] Unhealthy targets: Target deregistration is in progress: 1\n",
+ "INFO [12:28:32] Found endpoints:\n",
+ "INFO [12:28:32] - dev.aws-us-east-1c\n",
+ "INFO [12:28:32] |-- https://b0502030.a13b2ab6.z.vespa-app.cloud/ (cluster 'authdemo_container')\n",
+ "INFO [12:28:33] Unhealthy targets: Target deregistration is in progress: 1\n",
+ "INFO [12:28:43] Found endpoints:\n",
+ "INFO [12:28:43] - dev.aws-us-east-1c\n",
+ "INFO [12:28:43] |-- https://b0502030.a13b2ab6.z.vespa-app.cloud/ (cluster 'authdemo_container')\n",
+ "INFO [12:28:43] Unhealthy targets: Target deregistration is in progress: 1\n",
+ "INFO [12:28:53] Found endpoints:\n",
+ "INFO [12:28:53] - dev.aws-us-east-1c\n",
+ "INFO [12:28:53] |-- https://b0502030.a13b2ab6.z.vespa-app.cloud/ (cluster 'authdemo_container')\n",
+ "INFO [12:28:53] Deployment of new application complete!\n",
+ "Found mtls endpoint for authdemo_container\n",
+ "URL: https://b0502030.a13b2ab6.z.vespa-app.cloud/\n",
+ "Connecting to https://b0502030.a13b2ab6.z.vespa-app.cloud/\n",
+ "Using mtls_key_cert Authentication against endpoint https://b0502030.a13b2ab6.z.vespa-app.cloud//ApplicationStatus\n",
+ "Application is up!\n",
+ "Finished deployment.\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "Vespa(https://b0502030.a13b2ab6.z.vespa-app.cloud/)"
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "vespa_cloud = VespaCloud(\n",
+ " tenant=tenant_name,\n",
+ " application=application,\n",
+ " key_content=key,\n",
+ " application_package=app_package,\n",
+ ")\n",
+ "vespa_cloud.deploy()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "76978e65",
+ "metadata": {},
+ "source": [
+ "Note that a Vespa application creates a separate URL endpoint for each auth-client added.\n",
+ "Here is how you can retrieve the URL for the token endpoint:\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "dc48fe2d",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Found token endpoint for authdemo_container\n",
+ "URL: https://a11f9017.a13b2ab6.z.vespa-app.cloud/\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "'https://a11f9017.a13b2ab6.z.vespa-app.cloud/'"
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "token_endpoint = vespa_cloud.get_token_endpoint()\n",
+ "token_endpoint"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "15961d29",
+ "metadata": {},
+ "source": [
+ "## Re-connecting to a deployed application\n",
+ "\n",
+ "To connect to a deployed application, you can use the `Vespa` class, which is a data-plane connection to an existing Vespa application.\n",
+ "\n",
+ "The `Vespa` class requires the endpoint URL.\n",
+ "\n",
+ "Note that this class can also be instantiated without authentication, typically used if connecting to an instance running in Docker, see [VespaDocker](https://pyvespa.readthedocs.io/en/latest/reference-api.html#vespadocker).\n",
+ "\n",
+ "### Connecting using mTLS\n",
+ "\n",
+ "To connect to the Vespa application using mTLS, you must pass `key` and `cert` to the `Vespa` class.\n",
+ "Both should be a path to the respective files, matching the cert that was added to the application package upon deployment.\n",
+ "\n",
+ "A common error is to try to regenerate the key/cert after deployment, causing a mismatch between the key/cert you are trying to authenticate with, and the cert added to the application package.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "id": "518e41db",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "\n",
+ "# Get user home directory\n",
+ "home = os.path.expanduser(\"~\")\n",
+ "# Vespa key/cert directory\n",
+ "app_dir = f\"{home}/.vespa/{tenant_name}.{application}.default/\"\n",
+ "\n",
+ "cert_path = f\"{app_dir}/data-plane-public-cert.pem\"\n",
+ "key_path = f\"{app_dir}/data-plane-private-key.pem\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "id": "e107e9f7",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Using mtls_key_cert Authentication against endpoint https://b0502030.a13b2ab6.z.vespa-app.cloud//ApplicationStatus\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "from vespa.application import Vespa\n",
+ "\n",
+ "app = Vespa(url=mtls_endpoint, cert=cert_path, key=key_path)\n",
+ "app.get_application_status()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7208db48",
+ "metadata": {},
+ "source": [
+ "#### Using `requests`\n",
+ "\n",
+ "It is often overlooked that all interactions with Vespa are through HTTP-api calls, so you are free to use any HTTP client you like.\n",
+ "\n",
+ "Below is an example of how to use the `requests` library to interact with Vespa, using `key` and `cert` for authentication, and the [`/document/v1/`](https://docs.vespa.ai/en/reference/document-v1-api-reference.html) endpoint to feed data to Vespa.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "id": "63130058",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'pathId': '/document/v1/doc/doc/docid/1', 'id': 'id:doc:doc::1'}"
+ ]
+ },
+ "execution_count": 12,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "import requests\n",
+ "\n",
+ "session = requests.Session()\n",
+ "session.cert = (cert_path, key_path)\n",
+ "url = f\"{mtls_endpoint}/document/v1/doc/doc/docid/1\"\n",
+ "data = {\n",
+ " \"fields\": {\n",
+ " \"id\": \"id:doc:doc::1\",\n",
+ " \"title\": \"the title\",\n",
+ " \"body\": \"the body\",\n",
+ " }\n",
+ "}\n",
+ "resp = session.post(url, json=data).json()\n",
+ "resp"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "397f2076",
+ "metadata": {},
+ "source": [
+ "## Connecting using token\n",
+ "\n",
+ "To connect to the Vespa application using a token, you must pass the token value to the `Vespa` class as `vespa_cloud_secret_token`.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "id": "b9fb5501",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Using token Authentication against endpoint https://a11f9017.a13b2ab6.z.vespa-app.cloud//ApplicationStatus\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 14,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "app = Vespa(\n",
+ " url=token_endpoint, vespa_cloud_secret_token=os.getenv(\"VESPA_CLOUD_SECRET_TOKEN\")\n",
+ ")\n",
+ "app.get_application_status()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bf0d4364",
+ "metadata": {},
+ "source": [
+ "### Using cURL\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5cae7ef3",
+ "metadata": {},
+ "source": [
+ "Token authentication provides an even more convenient way to authenticate to the data-plane, as you do not need to handle key/cert files, and can just add the token to the HTTP header, as shown in the example below.\n",
+ "\n",
+ "```bash\n",
+ "curl -H \"Authorization: Bearer $TOKEN\" https://{endpoint}/document/v1/{document-type}/{document-id}\n",
+ "```\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d1872b31",
+ "metadata": {},
+ "source": [
+ "## Next steps\n",
+ "\n",
+ "This was a guide to the different authentication methods when interacting with Vespa Cloud for different purposes.\n",
+ "\n",
+ "Try to deploy a frontend as interface to your Vespa application.\n",
+ "\n",
+ "Example of some providers are:\n",
+ "\n",
+ "- [Cloudflare Workers](https://workers.cloudflare.com/), see also [https://cloud.vespa.ai/en/security/cloudflare-workers.html](https://cloud.vespa.ai/en/security/cloudflare-workers.html)\n",
+ "- [Vercel](https://vercel.com/)\n",
+ "- [Railway](https://railway.app/)\n",
+ " etc.\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7cc41490",
+ "metadata": {},
+ "source": [
+ "## Cleanup\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "66354a53",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Deactivated vespa-team.authdemo in dev.aws-us-east-1c\n",
+ "Deleted instance vespa-team.authdemo.default\n"
+ ]
+ }
+ ],
+ "source": [
+ "vespa_cloud.delete()"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.19"
+ },
+ "nbsphinx": {
+ "allow_errors": true
+ },
+ "vscode": {
+ "interpreter": {
+ "hash": "b0fa6594d8f4cbf19f97940f81e996739fb7646882a419484c72d19e05852a7e"
+ }
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/docs/sphinx/source/index.rst b/docs/sphinx/source/index.rst
index e7d5bbbd..57b10239 100644
--- a/docs/sphinx/source/index.rst
+++ b/docs/sphinx/source/index.rst
@@ -15,6 +15,7 @@ Vespa python API
getting-started-pyvespa
getting-started-pyvespa-cloud
+ authenticating-to-vespa-cloud
application-packages
query
reads-writes
diff --git a/docs/sphinx/source/reference-api.rst b/docs/sphinx/source/reference-api.rst
index da8af4fc..b0a73a91 100644
--- a/docs/sphinx/source/reference-api.rst
+++ b/docs/sphinx/source/reference-api.rst
@@ -111,6 +111,29 @@ ApplicationConfiguration
:members:
:special-members: __init__
+AuthClient
+**********
+.. autoclass:: vespa.package.AuthClient
+ :members:
+ :special-members: __init__
+
+Component
+*********
+.. autoclass:: vespa.package.Component
+ :members:
+ :special-members: __init__
+
+ContainerCluster
+****************
+.. autoclass:: vespa.package.ContainerCluster
+ :members:
+ :special-members: __init__
+
+ContentCluster
+**************
+.. autoclass:: vespa.package.ContentCluster
+ :members:
+ :special-members: __init__
Document
********
@@ -167,6 +190,11 @@ ImportedField
:members:
:special-members: __init__
+Nodes
+*****
+.. autoclass:: vespa.package.Nodes
+ :members:
+ :special-members: __init__
OnnxModel
*********
diff --git a/vespa/package.py b/vespa/package.py
index 1309c1f1..4efbc3ee 100644
--- a/vespa/package.py
+++ b/vespa/package.py
@@ -1787,7 +1787,7 @@ def __init__(
"""
Create a Vespa AuthClient.
- Check the `Vespa documentation `__
+ Check the `Vespa documentation