Skip to content

Add "access token" method to credentials #2929

Closed

Description

@coryan

We have at couple of requests to fetch the access token. A few observations:

  • The token should include the string value and the expiration time.
  • The token should be wrapped in a CacheableResource<>.
  • We should return an error for API keys.

  • we need direct access to an access token to integrate with existing libraries like object_store. object_store has pretty rudimentary support for how it does gcloud auth, we were aiming to use your first party auth library to make it more complete/customized for our specific environments.

@sai-sunder-s now that we have a clear need, we should restore the second method in Credentials to fetch the token. It would need to be something like:

impl Credentials {
  async pub fn access_token(&self, ...) -> Result<CacheableResource<AccessToken>>;

because it can fail to fetch the token (or the credential type may not support tokens at all) and you may want to cache a derived value and avoid recomputation. And AccessToken would be something like:

struct AccessToken { /* all private */}
impl AccessToken {
  pub fn value(&self) -> String;
  pub fn type(&self) -> &'static str; // typically `Bearer`
  pub fn expiration_time(&self) -> std::time::Instant /* ??? SystemTime ??? */
}

We also need to consider how to create tokens for mocking.

Originally posted by @coryan in #2879

Activity

  1. added
    type: feature request‘Nice-to-have’ improvement, new feature or different behavior or design.
    priority: p3Desirable enhancement or fix. May not be included in next release.
    authIssues related to the auth library
    on Aug 19, 2025
  2. nvnmandadhi commented on Aug 19, 2025

    @nvnmandadhi
    Contributor

    I would like to work on this.

  3. dbolduc commented on Aug 19, 2025

    @dbolduc
    Member

    We should return an error for API keys.

    Or we can keep Credentials as it is. It just gives you headers. gax doesn't change; it only cares about headers.

    And we have all of the existing credential builders (except for api_key) return an AccessTokenCredentials with an impl Credentials for AccessTokenCredentials.

    We split out API key into its own ApiKeyCredentials, also with an impl Credentials for ApiKeyCredentials.

    And later we add IdTokenCredentials with their own API

  4. self-assigned this
    on Sep 23, 2025
  5. alvarowolfx commented on Oct 28, 2025

    @alvarowolfx
    Contributor

    We should return an error for API keys.

    Or we can keep Credentials as it is. It just gives you headers. gax doesn't change; it only cares about headers.

    And we have all of the existing credential builders (except for api_key) return an AccessTokenCredentials with an impl Credentials for AccessTokenCredentials.

    We split out API key into its own ApiKeyCredentials, also with an impl Credentials for ApiKeyCredentials.

    And later we add IdTokenCredentials with their own API

    @dbolduc I came back to this and wanted to get more your thoughts on this. You mentioned doing impl Credentialls, but Credentials is a struct, not a trait, which makes harder to add a new AccessTokenCredential type that can replace it and avoid a breaking change. Speaking of breaking change, not sure if just adding a token method to the Credential struct would even be a breaking change, because that's the easiest solution.

    One idea that I was gonna start to evaluate is to add a new build_access_token_credentials() method to all the Credentials builders (excepts API Token), that then return a AccessTokenCredential struct that implements a AccessTokenProvider trait that has a token method. This avoids a breaking change, but introduces a whole set of structs just for Access Token

  6. dbolduc commented on Oct 28, 2025

    @dbolduc
    Member

    You mentioned doing impl Credentials, but Credentials is a struct, not a trait, which makes harder to add a new AccessTokenCredential type that can replace it and avoid a breaking change.

    I think I made the post before we had released 1.0, but probably too late.

    Speaking of breaking change, not sure if just adding a token method to the Credential struct would even be a breaking change, because that's the easiest solution.

    Adding fns to a struct is not a breaking change1. It would only be a breaking change on a trait if it does not have a default implementation and the trait is not sealed.

    your thoughts

    My thoughts were generally that Access Tokens, API Keys, and ID tokens are different things. We don't have to unify them.

    Access tokens and API keys are used in headers to auth a request. So having a trait that both implement would be nice for gax, or any other application that uses google auth directly.

    Having an API key credential with a fn token() that just errors every time is a smelly design. It may be the best way forward, but I doubt we would opt to do that if we rewrote the library from scratch. That is the sort of thing I wanted to avoid.

    One idea that I was gonna start to evaluate is to add a new build_access_token_credentials() method to all the Credentials builders (excepts API Token), that then return a AccessTokenCredential struct that implements a AccessTokenProvider trait that has a token method. This avoids a breaking change, but introduces a whole set of structs just for Access Token

    Yeah, this sounds similar to how I was thinking about it. Basically the Access Token umbrella (which has user creds, mds creds, SA creds, etc.) gets unified by some trait or opaque type. fn token() is well defined on it.

    API key credentials don't get fn token().

    I assume ID token credentials would return an ID token. (vs. an access token. I think we would not unify them. Applications use them differently. But you know more than I do. I am just guessing.)

    Footnotes

    1. It technically could be if someone defines a trait extension for the type with the same name as the function we are adding. I don't think we have ever considered this before, and note that we add new functions all the time for our generated structs. ↩

  7. alvarowolfx commented on Oct 29, 2025

    @alvarowolfx
    Contributor

    yeah, good points, I know that adding a function is not a breaking change in general, I was just afraid because Credentials can be extended by customers and is used extensively in the SDK. But in any case is a bad idea, since, like you mentioned, API Keys creds would have to throw an error, which is a bad design.

    Adding fns to a struct is not a breaking change1. It would only be a breaking change on a trait if it does not have a default implementation and the trait is not sealed.

    Having an API key credential with a fn token() that just errors every time is a smelly design. It may be the best way forward, but I doubt we would opt to do that if we rewrote the library from scratch. That is the sort of thing I wanted to avoid.

    Just to expand here, ID Tokens are way too different to access tokens, both in format ( access tokens are opaque tokens, id tokens are JWTs) and also they have different parameters and requirements to be set up (like audience being required for id tokens). That's why id tokens have a separated trait and credential struct, which can be seen in the PR following #3449.

    I assume ID token credentials would return an ID token. (vs. an access token. I think we would not unify them. Applications use them differently. But you know more than I do. I am just guessing.)

    For access tokens, the Builders/Credentials can be 100% reused, since just the end goal of how such access token is gonna be consumed is different. I'll explore this path of having a new build_acess_token_something on the existing Builders.

    Yeah, this sounds similar to how I was thinking about it. Basically the Access Token umbrella (which has user creds, mds creds, SA creds, etc.) gets unified by some trait or opaque type. fn token() is well defined on it.

    Thanks for sharing your thoughts @dbolduc

  8. added this to the Q4 Auth Features milestone on Oct 29, 2025
  9. added a commit that references this issue on Nov 25, 2025
    37aef82
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

authIssues related to the auth librarypriority: p3Desirable enhancement or fix. May not be included in next release.type: feature request‘Nice-to-have’ improvement, new feature or different behavior or design.

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions