Adding user authorization to your tools
Outcomes
Create a that sends a message on behalf of a via Slack.
You will Learn
- How to add user authorization to your custom with Arcade.
- How to use the
ToolContextclass to make authenticated requests to external APIs. - How to use the
Slackto authorize your .
Prerequisites
- An Arcade account
- For this guide, we’ll use uv as our package manager.
- Set up Arcade CLI
- Understand Tool Context
Install Arcade and Slack SDK
uv
uv pip install arcade-ai slack_sdkDefine your authorized tool
Create a new Python file, e.g., slack_tools.py, and import the necessary modules:
from typing import Annotated
from arcade_tdk import ToolContext, tool
from arcade_tdk.auth import Slack
from arcade_tdk.errors import RetryableToolError
from slack_sdk import WebClientNow, define your using the @tool decorator and specify the required authorization, in this case, by using the built-in Slack :
@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"],
) -> Annotated[str, "A confirmation message that the DM was sent"]:
"""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)
return "DM sent successfully"Arcade offers a number of built-in auth providers, including Slack, Google, and GitHub. You can also require authorization with a custom , 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 in
the . 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
that won’t be shared.
Use your authorized tool with Arcade
Now you can use your custom authorized with Arcade in your application.
Here’s an example of how to use your :
from arcadepy import Arcade
client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
user_id = "{arcade_user_id}"
# Use the tool
response = client.tools.execute(
tool_name="Slack.SendDmToUser",
input={
"user_name": "johndoe",
"message": "Hello!",
},
user_id=user_id,
)
print(response.output.value)Handle authorization
Since your requires authorization, the first time you use it, the (identified by user_id) needs to authorize access.
Arcade handles the authorization flow, prompting the to visit a URL to grant permissions.
Your application should guide the through this process.
How it works
By specifying the requires_auth parameter in the @tool decorator, you indicate that the needs authorization.
Arcade manages the OAuth flow, and provides the token in context.authorization.token when the is executed. Arcade also remembers the ’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 , or explore how to handle different authorization providers and scopes.