feat: delegated auth support — token forwarding and principal-based resolver#36
Open
feat: delegated auth support — token forwarding and principal-based resolver#36
Conversation
Ai::Agent now accepts delegated_auth: (Access, Company, or any principal) instead of delegated_token:. The principal is resolved to a token string via the configurable Ai.delegated_token_resolver callback. delegated_token: remains on the Ai::Client layer (internal transport).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🚪 Why?
Mastra agents need to authenticate with the Factorial backend when triggered by backend events (no user session). This PR adds the full delegated auth chain to
ruby-ai-client: forwarding tokens to Mastra via HTTP headers, and adelegated_auth:parameter onAi::Agentthat resolves principals (Access or Company) to tokens through a configurable callback — so callers just pass the principal without manually minting tokens.🔑 What?
Token forwarding:
Ai::Clientbase class,Ai::Clients::Mastra, andAi::Clients::Testaccept an optionaldelegated_token:keyword ongenerateandrun_workflow.Mastraclient forwards it asX-Factorial-Delegated-BearerHTTP header on all requests (agent generate, workflow create-run, stream, and result-fetch).Principal-based resolver:
Ai.delegated_token_resolverconfig accessor — the host application sets a lambda that resolves a principal (e.g. Access, Company) to a token string.Ai::Agent#generate_textand#generate_objectacceptdelegated_auth:(any principal). Internally calls the resolver to get the token, then passes it to the client layer.delegated_auth: nil(the default) skips resolution entirely — agents that don't need backend auth work unchanged.Ai::Errorifdelegated_auth:is provided but no resolver is configured.📐 New interfaces
Ai::Agent#generate_text/#generate_object— newdelegated_auth:parameterPass an Access or Company principal to authenticate Mastra's downstream calls to the backend. The agent resolves it to a Doorkeeper token internally via the configured resolver. Optional — agents that don't call the backend omit it.
Ai.delegated_token_resolver— new config accessorThe host application configures a lambda that maps a principal to a token string. Set once in an initializer:
Ai::Client#generate/#run_workflow— newdelegated_token:parameter (internal)The client layer accepts a raw token string and the Mastra client forwards it as the
X-Factorial-Delegated-BearerHTTP header. This is internal plumbing — callers should useAi::Agentwithdelegated_auth:instead.🏡 Context