Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 152 additions & 0 deletions contributing/samples/authn-adk-all-in-one/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
## ADK Authentication Demo (All in one - Agent, IDP and The app)

This folder contains everything you need to run the ADK's `auth-code`
grant type authentication demo completely locally

Here's the high level diagram.

![alt](doc_images/adk-auth-all-in-one.svg)

### Introduction
More often than not the agents use some kind of system identity
(especially for OpenAPI and MCP tools).
But obviously this is insecure in that multiple end users
are using the same identity with permissions to access ALL users' data on the
backend.

ADK provides various [authentication mechanisms](https://google.github.io/adk-docs/tools/authentication/) to solve this.

However to properly test it you need various components.
We provide everything that is needed so that you can test and run
ADK authentication demo locally.

This folder comes with -

1. An IDP
2. A hotel booking application backend
3. A hotel assistant ADK agent (accessing the application using OpenAPI Tools)

### Details

You can read about the Auth Code grant / flow type in detail [here](https://developer.okta.com/blog/2018/04/10/oauth-authorization-code-grant-type). But for the purpose of this demo, following steps take place

1. The user asks the agent to find hotels in "New York".
2. Agent realizes (based on LLM response) that it needs to call a tool and that the tool needs authentication.
3. Agent redirects the user to the IDP's login page with callback / redirect URL back to ADK UI.
4. The user enters credentials (`john.doe` and `password123`) and accepts the consent.
5. The IDP sends the auth_code back to the redirect URL (from 3).
6. ADK then exchanges this auth_code for an access token.
7. ADK does the API call to get details on hotels and hands over that response to LLM, LLM formats the response.
8. ADK sends a response back to the User.

### Setting up and running

1. Clone this repository
2. Carry out following steps and create and activate the environment
```bash
# Go to the cloned directory
cd adk-python
# Navigate to the all in one authentication sample
cd contributing/samples/authn-adk-all-in-one/

python3 -m venv .venv

. .venv/bin/activate

pip install -r requirements.txt

```
3. Configure and Start the IDP. Our IDP needs a private key to sign the tokens and a JWKS with public key component to verify them. Steps are provided for that (please check the screenshots below)

🪧 **NOTE:**
It is recommended that you execute the key pair creation and public
key extraction commands (1-3 and 5 below) on Google cloud shell.

```bash
cd idp

# Create .env file by copying the existing one.
cp sample.env .env
cp sample.jwks.json jwks.json


# Carry out following steps
# 1. Generate a key pair, When asked about passphrase please press enter (empty passphrase)
ssh-keygen -t rsa -b 2048 -m PEM -f private_key.pem

# 2. Extract the public key
openssl rsa -in private_key.pem -pubout > pubkey.pub

# 3. Generate the jwks.json content using https://jwkset.com/generate and this public key (choose key algorithm RS256 and Key use Signature) (Please check the screenshot)
# 4. Update the jwks.json with the key jwks key created in 3 (please check the screenshot)
# 5. Update the env file with the private key
cat private_key.pem | tr -d "\n"
# 6. Carefully copy output of the command above into the .env file to update the value of PRIVATE_KEY
# 7. save jwks.json and .env

# Start the IDP
python app.py
```
<details>

<summary><b>Screenshots</b></summary>
Generating JWKS -

![alt](doc_images/jwksgen.png)

Updated `jwks.json` (notice the key is added in the existing array)

![alt](doc_images/jwks_updated.png)

</details>

4. In a separate shell - Start the backend API (Hotel Booking Application)
```bash
# Go to the cloned directory
cd adk-python
# Navigate to the all in one authentication sample
cd contributing/samples/authn-adk-all-in-one/

# Activate Env for this shell
. .venv/bin/activate

cd hotel_booker_app/

# Start the hotel booker application
python main.py

```

5. In a separate shell - Start the ADK agent
```bash
# Go to the cloned directory
cd adk-python
# Navigate to the all in one authentication sample
cd contributing/samples/authn-adk-all-in-one/

# Activate Env for this shell
. .venv/bin/activate

cd adk_agents/

cp sample.env .env

# ⚠️ Make sure to update the API KEY (GOOGLE_API_KEY) in .env file

# Run the agent
adk web

```
6. Access the agent on http://localhost:8000

🪧 **NOTE:**

After first time authentication,
it might take some time for the agent to respond,
subsequent responses are significantly faster.

### Conclusion

You can exercise the ADK Authentication
without any external components using this demo.

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from . import agent
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import logging
import os

from google.adk.tools.openapi_tool.auth.auth_helpers import openid_url_to_scheme_credential
from google.adk.tools.openapi_tool.openapi_spec_parser.openapi_toolset import OpenAPIToolset

credential_dict = {
"client_id": os.environ.get("OAUTH_CLIENT_ID"),
"client_secret": os.environ.get("OAUTH_CLIENT_SECRET"),
}
auth_scheme, auth_credential = openid_url_to_scheme_credential(
openid_url="http://localhost:5000/.well-known/openid-configuration",
credential_dict=credential_dict,
scopes=[],
)


# Open API spec
file_path = "./agent_openapi_tools/openapi.yaml"
file_content = None

try:
with open(file_path, "r") as file:
file_content = file.read()
except FileNotFoundError:
# so that the execution does not continue when the file is not found.
raise FileNotFoundError(f"Error: The API Spec '{file_path}' was not found.")


# Example with a JSON string
openapi_spec_yaml = file_content # Your OpenAPI YAML string
openapi_toolset = OpenAPIToolset(
spec_str=openapi_spec_yaml,
spec_str_type="yaml",
auth_scheme=auth_scheme,
auth_credential=auth_credential,
)

from google.adk.agents import LlmAgent

root_agent = LlmAgent(
name="hotel_agent",
instruction=(
"Help user find and book hotels, fetch their bookings using the tools"
" provided."
),
description="Hotel Booking Agent",
model=os.environ.get("GOOGLE_MODEL"),
tools=[openapi_toolset], # Pass the toolset
# ... other agent config ...
)
Loading