Skip to content

Introduce an ApiKey Abstraction to enable Dynamic ApiKeys #1706

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

Closed
wants to merge 1 commit into from

Conversation

asaikali
Copy link

@asaikali asaikali commented Nov 9, 2024

Some model providers use short-lived api keys which must be renewed at regular intervals using another credential. For example, a GCP service account can be exchanged for an api key to call Vertex AI.

A StaticApiKey implementation is provided for API providers that use long lived api keys. OpenAiApi class was changed so that it accepts an ApiKey instead of a String which caused a lot small changes in downstream integration tests and auto configurations that were creating a OpenAiApi using a String key.

Model provider specific implementations of the ApiKey interface will be in a future commit.

Some model providers use short-lived api keys which must be renewed at regular
intervals using another credential. For example, a GCP service account can be exchanged
for an api key to call Vertex AI.

A StaticApiKey implementation is provided for API providers that use long lived api
keys. OpenAiApi class was changed so that it accepts an ApiKey instead of a String
which caused a lot small changes in downstream integration tests and auto configurations
that were creating a OpenAiApi using a String key.

Model provider specific implementations of the ApiKey interface will be in a future
commit.
*
* @author Adib Saikali
*/
public interface ApiKey {
Copy link
Member

@markpollack markpollack Nov 11, 2024

Choose a reason for hiding this comment

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

this should likely extend Supplier<String> Perhaps it should return a more rich type such as Key that contains a String but would be open for other fields.

Copy link
Author

Choose a reason for hiding this comment

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

for models called using http they will typically use the an Authorization: header which should have a string value, and if we want to support none string value we can add something like getValueAsXYZ to the ApiKey interface. I can see the ApiKey interface with extra methods to get metadata about keys, so 100% agree we should have a rich type to represent a key.

The ApiKey interface is the rich interface I did not want to call it Key because that name is too generic and has multiple meaning in the security context for example encryption key ... etc.

I think using Supplier makes a lot of sense, I except something like this would be needed in the auto configuration layer. However, I have not touched the auto configuration layer, to keep the scope of the PR small.

I thought about using Supplier<ApiKey> in the OpenAiApi class

Instead of

public class OpenAiApi {
	public OpenAiApi(ApiKey apiKey) {
		this(OpenAiApiConstants.DEFAULT_BASE_URL, apiKey);
	}

change to something like

public class OpenAiApi {
	public OpenAiApi(Supplier<ApiKey> apiKey) {
		this(OpenAiApiConstants.DEFAULT_BASE_URL, apiKey);
	}

The downside of making such a change is that it makes the call sites where OpenAiApi is instantiated in numerous test cases full of boiler plate around Supplier. We have a lot of lines code that look like this

OpenAiApi openAiApi = new OpenAiApi(new StaticApiKey(System.getenv("OPENAI_API_KEY")));

if we change

public interface ApiKey {

	/**
	 * Returns an api key to use for a making request. Users of this method should NOT
	 * cache the returned api key, instead call this method whenever you need an api key.
	 * Implementors of this method MUST ensure that the returned key is not expired.
	 * @return the current value of the api key
	 */
	String getValue();
}

to

public interface ApiKey extends Supplier<String> {
}

then we can get rid of the getValue method since Supplier already has a method called value. but then we loose the javadoc defining the contract on the getValue method

Let me know how you want me to proceed.

@markpollack markpollack added this to the 1.0.0-M6 milestone Jan 21, 2025
@markpollack markpollack self-assigned this Jan 29, 2025
@markpollack
Copy link
Member

closing as it was address for openai at least in #2164 Will create an epic so that this approach can be applied across the other model providers.

@markpollack markpollack closed this Feb 6, 2025
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.

2 participants