Welcome to the final chapter of our RemoteTriggerTool tutorial!
In the previous chapter, API Action Dispatcher, we built the logic to route commands like "run" or "list" to specific URL addresses.
However, if you tried to run the tool now, you would hit a brick wall. The API would respond with 401 Unauthorized. Why? Because we haven't proven who we are.
Imagine a high-security VIP club. You can't just walk up to the bar and order a drink; you need to show your membership badge.
If we asked the user to type their secret API key every time they wanted to list triggers, it would be annoying and unsafe. They might accidentally paste it into a chat window or lose it.
Secure Context Injection is our solution. It acts like an automatic badge scanner.
We need to gather three specific pieces of information before we can make a call:
Let's look at the top of the call function in RemoteTriggerTool.ts to see how we gather these credentials.
First, we ensure the user is logged in. We access the internal authentication system to get the current token.
import {
checkAndRefreshOAuthTokenIfNeeded,
getClaudeAIOAuthTokens,
} from '../../utils/auth.js'
// Inside the call() method...
await checkAndRefreshOAuthTokenIfNeeded()
const accessToken = getClaudeAIOAuthTokens()?.accessToken
Explanation: checkAndRefresh... makes sure the token hasn't expired. If it has, it refreshes it automatically. Then we grab the accessToken string.
If the user isn't logged in, we stop immediately. We don't want to send a request that we know will fail.
if (!accessToken) {
throw new Error(
'Not authenticated. Run /login and try again.',
)
}
Explanation: This acts as a gatekeeper. If there is no badge, the tool throws an error and tells the user how to fix it (/login).
A user might belong to multiple organizations. We need to know which one they are currently acting in.
import { getOrganizationUUID } from '../../services/oauth/client.js'
const orgUUID = await getOrganizationUUID()
if (!orgUUID) {
throw new Error('Unable to resolve organization UUID.')
}
Explanation: getOrganizationUUID fetches the ID of the currently active workspace. We need this because the API needs to know which list of triggers to show us.
Now we pack everything into the headers object. This is what we attach to our outgoing message.
const headers = {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json',
'anthropic-version': '2023-06-01',
'anthropic-beta': 'ccr-triggers-2026-01-30',
'x-organization-uuid': orgUUID,
}
Explanation:
Finally, we pass these headers to our network client (Axios), which we set up in API Action Dispatcher.
const res = await axios.request({
method, // determined in Chapter 4
url, // determined in Chapter 4
headers, // <--- Injected here!
data,
})
Explanation: The dispatcher handles *where to go (URL), but the headers handle access rights to get in.*
What happens in the split second before the network request is sent?
The beauty of this system is that RemoteTriggerTool.ts doesn't need to know how to log in a user or how to refresh a token. It imports these capabilities from ../../utils/auth.js.
This separation of concerns means:
auth.js, and all tools update automatically.Congratulations! You have successfully built the RemoteTriggerTool from scratch.
Let's review our journey:
You now have a fully functional tool that allows an AI to securely manage remote triggers, complete with input validation, error handling, and a polished user interface.
Happy coding!
Generated by Code IQ