Adding user authorization to your tools
In this guide, you’ll learn how to add user authorization to your custom tools, using Arcade.
You’ll create a tool that sends a message on behalf of a user via Slack.
Prerequisites
- Set up Arcade
- Install the Arcade SDK and any third-party SDKs you need (e.g., Slack SDK):
- Understand Tool Context
pip install arcade-ai slack_sdk
Define your authorized tool
Create a new Python file, e.g., slack_tools.py
, and import the necessary modules:
from typing import Annotated
from arcade.sdk import ToolContext, tool
from arcade.sdk.auth import Slack
from arcade.sdk.errors import RetryableToolError
from slack_sdk import WebClient
Now, define your tool using the @tool
decorator and specify the required authorization, in this case, by using the built-in Slack
auth provider:
@tool(
requires_auth=Slack(
scopes=[
"chat:write",
"im:write",
"users.profile:read",
"users:read",
],
)
)
def send_dm_to_user(
context: ToolContext,
user_name: Annotated[str, "The Slack username of the person you want to message"],
message: Annotated[str, "The message you want to send"],
):
"""Send a direct message to a user in Slack."""
slack_client = WebClient(token=context.authorization.token)
# Retrieve the user ID based on username
user_list_response = slack_client.users_list()
user_id = None
for user in user_list_response["members"]:
if user["name"].lower() == user_name.lower():
user_id = user["id"]
break
if not user_id:
raise RetryableToolError(
"User not found",
developer_message=f"User with username '{user_name}' not found."
)
# Open a conversation and send the message
im_response = slack_client.conversations_open(users=[user_id])
dm_channel_id = im_response["channel"]["id"]
slack_client.chat_postMessage(channel=dm_channel_id, text=message)
Arcade offers a number of built-in auth providers, including Slack, Google, and GitHub. You can also require authorization with a custom auth provider, using the OAuth2
class, a subclass of the ToolAuthorization
class:
@tool(
requires_auth=OAuth2(
id="your-oauth-provider-id",
scopes=["scope1", "scope2"],
)
)
The OAuth2
class requires an id
parameter to identify the auth provider in the Arcade Engine. For built-in providers like Slack
, you can skip the id
- the Arcade Engine will find the right provider using your credentials. While you can specify an id
for built-in providers, only do this for private tools that won’t be shared.
Register your tool
As before, you need to register your tool in a ToolCatalog
:
from arcade.sdk import ToolCatalog
from slack_tools import send_dm_to_user
catalog = ToolCatalog()
catalog.add_tool(send_dm_to_user)
Use your authorized tool with Arcade
Now you can use your custom authorized tool with Arcade in your application.
Here’s an example of how to use your tool:
from arcadepy import Arcade
from catalog import catalog
client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
user_id = "[email protected]"
# Use the tool in a chat completion
response = client.chat.completions.create(
messages=[
{
"role": "user",
"content": "Send a message to johndoe on Slack saying 'Hello!'",
}
],
model="gpt-4o",
tools=list(catalog.tools.keys()),
tool_choice="auto",
user=user_id,
)
print(response.choices[0].message.content)
Handle authorization
Since your tool requires authorization, the first time you use it, the user (identified by user_id
) needs to authorize access.
Arcade handles the authorization flow, prompting the user to visit a URL to grant permissions.
Your application should guide the user through this process.
How it works
By specifying the requires_auth
parameter in the @tool
decorator, you indicate that the tool needs user authorization.
Arcade manages the OAuth flow, and provides the token in context.authorization.token
when the tool is executed. Arcade also remembers the user’s authorization tokens, so they won’t have to go through the authorization process again until the auth expires or is revoked.
Next steps
Try adding more authorized tools, or explore how to handle different authorization providers and scopes.