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

Allow providing a token argument #677

Closed
stephenplusplus opened this issue Apr 25, 2019 · 20 comments · Fixed by #1652
Closed

Allow providing a token argument #677

stephenplusplus opened this issue Apr 25, 2019 · 20 comments · Fixed by #1652
Assignees
Labels
priority: p3 Desirable enhancement or fix. May not be included in next release. type: feature request ‘Nice-to-have’ improvement, new feature or different behavior or design.

Comments

@stephenplusplus
Copy link
Contributor

Thanks to @rac0316's research, when @google-cloud/common switched from google-auto-auth to this library, we lost the token option.

Could we bring it back?

// @JustinBeckwith

@yoshi-automation yoshi-automation added triage me I really want to be triaged. 🚨 This issue needs some love. labels Apr 26, 2019
@bcoe bcoe added the type: feature request ‘Nice-to-have’ improvement, new feature or different behavior or design. label May 1, 2019
@yoshi-automation yoshi-automation removed 🚨 This issue needs some love. triage me I really want to be triaged. labels May 1, 2019
@grant
Copy link

grant commented Jun 11, 2019

This is a downstream (2x) issue that is blocking b/64476727

@tswast
See: googleapis/nodejs-bigquery#418

@tswast
Copy link

tswast commented Jun 11, 2019

Is that a refresh token or an access token? Ideally we could take a refresh token and needed client secrets in order to support user credentials.

@grant
Copy link

grant commented Jun 11, 2019

Access token. Click the token link in the bug description.

@JustinBeckwith
Copy link
Contributor

With the information I have now - I'm not in favor of a feature like this one. Access tokens expire. If we add an API that accepts an access token without the expiration and refresh token, we're just setting folks up for failure when it invariably times out.

@rac0316 may I ask - what's the use case where you specifically want to provide an access token? Why

Adding @broady for his thoughts here as well.

@HuaRUAN
Copy link

HuaRUAN commented Jun 25, 2019

Running into the same situation. Downgraded to 1.3 works fine. The is a pivotal feature we use to give client a short time window of access to bq dataset.

@broady
Copy link
Contributor

broady commented Jun 25, 2019

-1 to "token" but +1 to a function or something that provides a token (a promise, since it often involves a network request, e.g. to refresh), so that it can cache and refresh as it needs.

as @JustinBeckwith says, token expiry makes this dangerously useful.

@HuaRUAN
Copy link

HuaRUAN commented Jun 25, 2019

Bq queries tend to be costly. How about we deliberately want to limit the bq usage? One token, no refresh.

@broady
Copy link
Contributor

broady commented Jun 25, 2019

What do you do after the token has expired?
In most cases, you don't actually want a static token, rather some token source that will always provide a valid token, refreshing if needed. (And caching still-valid tokens so you only refresh if you need to.)

In any case, a static token is handled pretty simply with a wrapper. In Go, this is called oauth2.StaticTokenSource

Roughly translated into broken JS:

const token = { token: "asdf", expiry: Date(...), ... }

let opts = {
  tokenSource: async () => {
    return token
  }
}

@HuaRUAN
Copy link

HuaRUAN commented Jun 25, 2019

Not sure if it is common use case. We have a server check against user ldap and issue this token. It is meant for an one-off job. If expires user will request another token. We do not want the refresh happening automatically, which will effectively give user indefinite access time without been notified.

@Tamirklein
Copy link

I think returning the feature as it was in 1.3.0 is a good start and improving it can be done in the future branch. Not having this feature disable us from providing service to the client based on their token which is a big miss

@komasoftware
Copy link

I am sending my access_token from my web client to a cloud function to access the Google Drive API. I know that my access_token will expire, I do not want to ask my users for offline access to get a refresh token, but rather stick with minimal permissions.

@MartinSahlen
Copy link

Don't know if it applies, but managed to override this issue in bigquery by doing this:
googleapis/nodejs-bigquery#68 (comment)

@JSAURAJ
Copy link

JSAURAJ commented Sep 23, 2019

What is the conclusion? Add token or do nothing?
I use access_token in older version, updating access_token manually with refresh token.
What is the way to use the bigquery 4.2.1 library using the oauht2 client? I can't find any example.

Thanks.

@tswast
Copy link

tswast commented Sep 25, 2019

I think Chris's tokenSource suggestion will be the most flexible (and consistent across languages). #677 (comment)

@glebsts
Copy link

glebsts commented Jan 19, 2021

Ran into same situation - our token is provided by hashicorp vault which app accesses by assuming some pod-embedded AWS roles, so we would like to set token manually and refresh also is our to manage. How can I put token or implement this tokenSource mentioned above?

@Farrukh-Rana
Copy link

We also have a usecase very similar to @glebsts usecase. We will be fetching temporary access tokens from hashicorp vault while the application is running and would ideally like to be able to pass (and set) access tokens to the underlying OAuthClient. Ofcourse building very vault specific refresh functionality within a common google auth library does not makes sense, so we would like to manage the lifecycle of the access tokens ourselves and simply want to be able to pass this access token to library client. For now, we have forked this library and will be building a hacky solution on top of it to provide the functionality of static access tokens. Would the maintainers of the library be interested if we opened up a (cleaned-up) PR for this static short-lived token functionality?

@fpoon
Copy link

fpoon commented Feb 18, 2022

Hi, we've come across this problem as well, while we were attempting to integrate BigQuery client with Vault managed tokens. As this issue seems to be stale, I want to share this snippet of static access token workaround for anyone else stumbling in here:

import {GetAccessTokenResponse, Headers} from "google-auth-library/build/src/auth/oauth2client"
import {GaxiosOptions, GaxiosPromise, GaxiosResponse} from "gaxios"
import {AuthClient} from "google-auth-library/build/src/auth/authclient"

class StaticAccessTokenAuthClient extends AuthClient {
    constructor(private readonly accessToken: string, protected quotaProjectId: string) {
        super()
    }

    getRequestHeaders(url?: string): Promise<Headers> {
        let headers = {
            Authorization: 'Bearer ' + this.accessToken
        } as Headers
        return Promise.resolve(
            this.addSharedMetadataHeaders(headers)
        )
    }

    // it seems that Service classes don't use this function, instead they make their own requests,
    // only incorporating headers from getRequestHeaders
    request<T>(opts: GaxiosOptions): GaxiosPromise<T> {
        return this.requestAsync<T>(opts)
    }

    private async requestAsync<T>(opts: GaxiosOptions): Promise<GaxiosResponse<T>> {
        opts.headers = {...opts.headers, ...await this.getRequestHeaders()}
        return Promise.resolve(this.transporter.request<T>(opts))
    }

    getAccessToken(): Promise<GetAccessTokenResponse> {
        return Promise.resolve({token: this.accessToken})
    }
}

let service = new BigQuery({projectId: "your-project-id"}) // or other client extending Service class from "@google-cloud/common"
let accessToken = getAccessToken() // your static access token
// acceptable types are restricted to JSONClient and Compute, but any AuthClient should do just fine
// @ts-ignore
service.authClient.cachedCredential = new StaticAccessTokenAuthClient(
    accessToken,
    service.projectId
)

Adjusting this code for Vault managed access tokens is fairly simple, just add function reading access token from Vault and pass it to getRequestHeaders method in place of static access token. There is a one caveat though, Service class seems to not use request method from auth client, so any solution based on replaying request with refreshed access token might fail. Instead, you need to keep track of token's TTL and refresh your access token within getRequestHeaders method.

I hope this issue will be resolved soon with some by-the-book solution (aforementioned clone of Golang's tokenSource looks cool), as authorization clients for other languages seem to already be capable of using access token provided by external services.

@itsbrianburton
Copy link

@JustinBeckwith @broady A specific Google-recommended use case is here: https://cloud.google.com/iam/docs/create-short-lived-credentials-direct Our microservices request a short-lived access token for each tenant and use that token to access their resources (bucket and database). No refresh tokens necessary.

We're dealing with this bug right now, and haven't found a working solution yet. Would love to give more visibility to this old issue.

@cr3ative
Copy link

As with @itsbrianburton, we just implemented this Google-recommended use case of short lived credentials, hit this problem, and had to implement a solution based on @fpoon's answer.

This was frustrating - it would be very welcome to see this functionality come back. I'm also in the "I create and refresh the token" category of user, I don't need this library to deal with refreshes.

@danielbankhead danielbankhead added the priority: p3 Desirable enhancement or fix. May not be included in next release. label May 11, 2023
@danielbankhead danielbankhead removed their assignment Jul 13, 2023
@danielbankhead danielbankhead self-assigned this Sep 27, 2023
@danielbankhead
Copy link
Member

danielbankhead commented Sep 29, 2023

I think these are valid use cases, especially if customers know what they're doing. In some cases, a customer may only have an access token without a refresh token [1] [2]. Rather than creating a new client we can simply support passing an access_token to OAuth2Client and ensuring it works as expected.

Usage:

const authClient = new OAuth2Client({credentials: {access_token: ''}});
await authClient.request({url});
await authClient.getAccessToken();

// can pass to other libraries, like `google-cloud/storage`
const storage = new Storage({authClient});
await storage.getBuckets();

However, I don't think this should be a part of the Application Default Credentials flow - this should be used by folks that know exactly what they're up to.

Happy to close out the oldest open issue in the repo 😃

PR: #1652

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
priority: p3 Desirable enhancement or fix. May not be included in next release. type: feature request ‘Nice-to-have’ improvement, new feature or different behavior or design.
Projects
None yet
Development

Successfully merging a pull request may close this issue.