Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve the internal consistency of credential handling #282

Merged
merged 1 commit into from
Jan 28, 2025

Conversation

atheriel
Copy link
Collaborator

This commit adopts the pattern used in chat_azure() to chat_databricks() and chat_snowflake(). That is: these providers now have a single credentials property that returns a list of headers when called.

In addition, there is now consistent internal usage of a default_x_credentials() function that itself returns a credentials function.

(Through experimenting with various designs, I decided that a simple function factory approach was preferable to the heavyweight S7 classes and generics approach I thought we could use initially.)

Finally, I've added several new unit tests for Databricks and Snowflake authentication.

Closes #262.

Copy link
Member

@hadley hadley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to confirm that I understand what's going on, there's currently no cache invalidation if the request fails due to the token expiring, right? It's only invalidated if the token is out of date (based on the expiration date given when it was first received)?

R/provider-cortex.R Outdated Show resolved Hide resolved
@@ -59,11 +59,16 @@ chat_databricks <- function(workspace = databricks_workspace(),
model <- set_default(model, "databricks-dbrx-instruct")
turns <- normalize_turns(turns, system_prompt)
echo <- check_echo(echo)
if (!is.null(token)) {
credentials <- function() list(Authorization = paste("Bearer", token))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want to allow manual credentials here too?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I really want to encourage folks to use authentication setups that are compatible with other Databricks tooling, which use environment variables. If anyone starts asking for an "escape hatch", though we could consider it then.

@hadley
Copy link
Member

hadley commented Jan 28, 2025

If we wanted to make this easier to do in httr2, I think we'd just need to export req_auth_sign() — this lets you define a callback to sign the request just before it's performed. It's also called once (with reauth = TRUE) if the request fails with an invalid oauth token (as defined by resp_is_invalid_oauth_token()), so we might need to add an additional parameter to req_auth_sign() that lets you define the criteria for when a re-auth is needed.

(This might already be obvious to you, but it's been a while since I looked at this code)

This commit adopts the pattern used in `chat_azure()` to
`chat_databricks()` and `chat_snowflake()`. That is: these providers now
have a single `credentials` property that returns a list of headers when
called.

In addition, there is now consistent internal usage of a
`default_x_credentials()` function that itself returns a `credentials`
function.

(Through experimenting with various designs, I decided that a simple
function factory approach was preferable to the heavyweight S7 classes
and generics approach I thought we could use initially.)

Finally, I've added several new unit tests for Databricks and Snowflake
authentication.

Closes #262.

Signed-off-by: Aaron Jacobs <[email protected]>
@atheriel
Copy link
Collaborator Author

I think if we did that, I could rewrite these credentials functions to take a req parameter, and then call req_auth_sign() inside of them, rather that having them return a list of headers. That could be a bit nicer, for sure. I'm a bit unsure if this is the "right" long-term design for custom authentication in httr2, though. Let me sit on it a bit more.

@atheriel atheriel force-pushed the internal-credentials-consistency branch from 9188021 to 82cd70c Compare January 28, 2025 14:58
@atheriel
Copy link
Collaborator Author

atheriel commented Jan 28, 2025

I realize that maybe I should use that pattern anyway so that we handle the OAuth token flows more correctly. Right now we get httr2's caching but not its reauth = TRUE behaviour -- for that I should use e.g. req_oauth_client_credentials(), which goes though req_auth_sign under the hood.

@atheriel
Copy link
Collaborator Author

My current feeling is that figuring out what to do about req_auth_sign() here shouldn't hold up the release, so I think it makes sense to merge as-is.

@hadley
Copy link
Member

hadley commented Jan 28, 2025

Yeah, agreed. Feel free to merge.

@atheriel atheriel merged commit 33bacb3 into main Jan 28, 2025
11 checks passed
@atheriel atheriel deleted the internal-credentials-consistency branch January 28, 2025 21:43
@hadley
Copy link
Member

hadley commented Jan 28, 2025

Hmmm, maybe the reauth argument shouldn't even exist — instead the auth function would expose a cache object that would be reset if auth failed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

More sophisticated internal APIs for credentials
2 participants