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

feat: support for API Key client option #351

Merged
merged 25 commits into from
Oct 31, 2024
Merged

Conversation

bshaffer
Copy link
Contributor

@bshaffer bshaffer commented Nov 15, 2021

Adds support for API Keys in GAPIC clients via a new apiKey client option:

$productSearchClient = new ProductSearchClient([
    'apiKey' => $myApiKey
]);

AIP: https://google.aip.dev/auth/4110

  • Supports the apiKey client option - this will be sent in using the x-goog-api-key header for all transports.
  • If the apiKey and credentials or credentialsConfig.keyFile option are supplied, an exception is thrown
  • If the apiKey option AND the quotaProject option are set, the $quotaProject is still sent in

@bshaffer bshaffer requested review from a team as code owners November 15, 2021 18:36
@google-cla google-cla bot added the cla: yes This human has signed the Contributor License Agreement. label Nov 15, 2021
@bshaffer bshaffer force-pushed the add-apikey-client-option branch from e6bb5c8 to b23a426 Compare November 23, 2021 14:47
@bshaffer bshaffer changed the title WIP: support for API Key RFC: support for API Key Feb 23, 2022
@bshaffer bshaffer changed the title RFC: support for API Key feat: support for API Key client option Dec 6, 2022
@vishwarajanand
Copy link
Contributor

@bshaffer Is this still in works, else we can close this?
The AIP now doesn't seem to talk about the apiKey?

@bshaffer
Copy link
Contributor Author

@vishwarajanand looking at the changelog, guidance for the API Key variable was removed. Let's check with the auth team and see what the status is on supporting API keys

@TimurSadykov what are your thoughts on this one?

@TimurSadykov
Copy link

I think the latest is that we don't add a generic support in auth libraries
@arithmetic1728 to confirm and reference a doc

@arithmetic1728
Copy link

we are not going to add a generic support for api key due to multiple push backs

@bshaffer
Copy link
Contributor Author

Closing for now

@bshaffer bshaffer closed this Sep 25, 2023
@bshaffer bshaffer deleted the add-apikey-client-option branch November 13, 2023 20:57
@bshaffer bshaffer restored the add-apikey-client-option branch July 10, 2024 21:39
@bshaffer bshaffer reopened this Sep 11, 2024
Comment on lines 264 to 267
// If the user has explicitly set the apiKey option, use Api Key credentials
if (isset($credentialsConfig['apiKey'])) {
return ApiKeyHeaderCredentials::build($credentialsConfig);
}

Choose a reason for hiding this comment

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

I want to call out these two conditions from the API Key Design Doc.

  1. If both credentials and api key are explicitly set, return an error to the user.
  2. If api key is set, do not attempt the ADC flow.

I think the first condition is missing in this code.

Is the second condition also missing?

Copy link
Contributor Author

@bshaffer bshaffer Sep 19, 2024

Choose a reason for hiding this comment

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

In the block you've highlighted, the logic goes like this:

  • IF $credentials are null (e.g. credentials have not been explicitly set), THEN
    • IF the apiKey option has been set, THEN create ApiKeyHeaderCredentials
    • ELSE use applicationDefaultCredentials (this happens in CredentialsWrapper::build)

So no, the second condition is not missing.

I can add validation for the first at the top of this function.

class ApiKeyHeaderCredentials implements HeaderCredentialsInterface
{
private $apiKey;
private $quotaProject;

Choose a reason for hiding this comment

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

Do you foresee any issues to adding a universe domain?

I don't have any clear guidance now, but I think eventually it may be relevant

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We do have guidance on universe domain with API Key - because there is no way to tie the two together, the universe domain is decided based on the supplied client option... so, while there CAN be a universe domain, it is not possible for the API key to validate it.

@bshaffer bshaffer requested a review from westarle October 24, 2024 17:04
@bshaffer
Copy link
Contributor Author

@westarle PTAL!

Copy link

@westarle westarle left a comment

Choose a reason for hiding this comment

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

API Key interface looks good to me!

/**
* @return string|null The quota project associated with the credentials.
*/
public function getQuotaProject(): ?string
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit:
I think that it looks cleaner with a union type than with a ?. But with the new PHP update, I don't anymore haha.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am definitely undecided on this. I think sometimes the ? looks better (because it's more concise).

*
* @return callable Callable function that returns the API key header.
*/
public function getAuthorizationHeaderCallback($unusedAudience = null): ?callable
Copy link
Contributor

Choose a reason for hiding this comment

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

nit:
Type for $unusedAudience

public function getAuthorizationHeaderCallback(null|string $unusdeAudience = null): null|callable

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good idea! Done

@@ -261,6 +261,7 @@ private static function determineMtlsEndpoint(string $apiEndpoint)
private function createCredentialsWrapper($credentials, array $credentialsConfig, string $universeDomain)
{
if (is_null($credentials)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I know this was written already but all the cases return on each if. What if we forego the elseif for all of them?:

if (is_null($credentials) {
    return CredentialsWrapper::buidl($credentialsConfig, universeDomain);
}

if (is_string($credentials) || is_array($credentials)) {
    return CredentialsWrapper::build(['keyFile' => $credentials] + $credentialsConfig, $universeDomain);
}

if ($credentials instanceof FetchAuthTokenInterface) {
    authHttpHandler = $credentialsConfig['authHttpHandler'] ?? null;
    return new CredentialsWrapper($credentials, $authHttpHandler, $universeDomain);
}

if ($credentials instanceof CredentialsWrapper) {
    return $credentials;
}

throw new ValidationException(
     'Unexpected value in $auth option, got: ' .
     print_r($credentials, true)
);

I find it easier to read and more pleasing.

Copy link
Contributor Author

@bshaffer bshaffer Oct 29, 2024

Choose a reason for hiding this comment

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

Good catch, I totally agree!

Done.

@bshaffer bshaffer merged commit ab7f04f into main Oct 31, 2024
14 checks passed
@bshaffer bshaffer deleted the add-apikey-client-option branch October 31, 2024 22:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla: yes This human has signed the Contributor License Agreement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants