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

config.UserPassword will fail to call /oauth/token endpoint after the refresh token expired a second time #444

Open
gogolok opened this issue Feb 6, 2025 · 0 comments · May be fixed by #445 or #447

Comments

@gogolok
Copy link

gogolok commented Feb 6, 2025

I use the go-cfclient library to create one client that should run kind of 'forever'.
I create the go-cfclient configuration via

cfg, err := config.New(cfAPIUrl, config.UserPassword(cfUser, cfPassword))

Next I create a client via

cf, err := client.New(cfg)

There is an issue when fetching a new access token after the refresh token has expired a second time.
After the first time that the refresh token expired, the function threeLeggedAuthConfigFn gets called and
can retrieve new credentials (a new refresh token) via 'oauth2 Config.PasswordCredentialsToken'.

The second time the refresh token expires, the function threeLeggedAuthConfigFn will fail to get new credentials.
The error you will receive is

err = error executing GET request for /v3/stacks?page=1&per_page=50: error executing request, failed during HTTP request send: Get "https://api.system.00.cf.eu01.example.com/v3/stacks?page=1&per_page=50": Post "https://uaa.system.00.cf.eu01.example.com/oauth/token": context canceled
stacks = [] ; err = error executing GET request for /v3/stacks?page=1&per_page=50: error executing request, failed during HTTP request send: Get "https://api.system.00.cf.eu01.example.com/v3/stacks?page=1&per_page=50": Post "https://uaa.system.00.cf.eu01.example.com/oauth/token": context canceled

I've uploaded my demo code to https://github.com/gogolok/go-cfclient-issue-rg0 .

The hard coded assumption is that the refresh token expires after 4 minutes.
But you can change the following line in main.go to change the refreshInterval to your UAA's refresh token expiration time.

refreshInterval := 4 * 60 * time.Second // 4 minutes

If you set up the environment variables
CF_API
CF_USERNAME
CF_PASSWORD
you could run the demo code and hopefully observe the following error:

$ go run main.go
stacks = [0x1400019e630 0x1400019e6c0] ; err = <nil>
Sleeping for time interval 4m0s .

stacks = [0x140002f8480 0x140002f8510] ; err = <nil>
Sleeping for time interval 4m0s .

err = error executing GET request for /v3/stacks?page=1&per_page=50: error executing request, failed during HTTP request send: Get "https://api.system.00.cf.eu01.example.com/v3/stacks?page=1&per_page=50": Post "https://uaa.system.00.cf.eu01.example.com/oauth/token": context canceled
stacks = [] ; err = error executing GET request for /v3/stacks?page=1&per_page=50: error executing request, failed during HTTP request send: Get "https://api.system.00.cf.eu01.example.com/v3/stacks?page=1&per_page=50": Post "https://uaa.system.00.cf.eu01.example.com/oauth/token": context canceled
Sleeping for time interval 4m0s .

The UAA does not issue new refresh tokens when getting a new access token with the refresh_token request.
This is because of the setting config.tokenPolicy.refreshTokenRotate = false (default value) I guess.

I have a fix that works on my system, but I need to dig deeper to reason why my fix is correct.
I will then create a PR to fix this issue and discuss the fix.

@gogolok gogolok changed the title config.UserPassword will fail to call /oauth/auth endpoint after the refresh token expired a second time config.UserPassword will fail to call /oauth/token endpoint after the refresh token expired a second time Feb 6, 2025
gogolok added a commit to stackitcloud/go-cfclient that referenced this issue Feb 6, 2025
gogolok added a commit to stackitcloud/go-cfclient that referenced this issue Feb 6, 2025
gogolok added a commit to stackitcloud/go-cfclient that referenced this issue Feb 6, 2025
The request context has set up a deadline of value DefaultRequestTimeout.
The function CreateOAuth2TokenSource would store that context in the
token source creator. The token source creator would later try to create
a new Token(), but fail since the deadline would be reached.

The context passed to oauth2 package controls which HTTP client is used.
See the oauth2.HTTPClient variable.

Therefore fix the situation by passing an empty context to oauth2
package.

Fixes cloudfoundry#444
@gogolok gogolok linked a pull request Feb 6, 2025 that will close this issue
gogolok added a commit to stackitcloud/go-cfclient that referenced this issue Feb 10, 2025
The request context has set up a deadline of value DefaultRequestTimeout.
The function CreateOAuth2TokenSource would store that context in the
token source creator. The token source creator would later try to create
a new Token(), but fail since the deadline would be reached.

The context passed to oauth2 package controls which HTTP client is used.
See the oauth2.HTTPClient variable.

Therefore fix the situation by passing our http.Client instance only to
oauth2 package.

The oauth2 Config.PasswordCredentialsToken case will use the request's
context to ensure context deadline will be respected.

Fixes cloudfoundry#444
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
1 participant