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

User Principal OAuth2 (Three Legged, Authorization Code) does not include Refresh Token(s) #675

Open
YvanJAquino opened this issue Oct 12, 2023 · 3 comments

Comments

@YvanJAquino
Copy link

Hi there,

I'm seeing some unexpected behavior while interacting with oauth2.Config & oauth2.Token objects.

My client targets a Google Cloud OAuth Client ID (via the Oauth Consent Screens service AKA OAuth Brands). My client uses a web app type credential which exists in the following format:

{
  "web": {
      "client_id": "...",
      "project_id": "...",
      "auth_uri": "https://accounts.google.com/o/oauth2/auth",
      "token_uri": "https://oauth2.googleapis.com/token",
      "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
      "client_secret": "...",
      "redirect_uris": [
          "http://localhost",
          "https://oauth2-authorizer-service"
      ]
  }
}

Creating a config from this always works fine. I then update the redirect URL, generate a randomized state string, and generate an AuthCodeURL, specifying the oauth2.AccessTypeOffline option.

/ Local Fetch token initiates a request from the localhost; the user is responsible for
// providing the state and auth code.
func (tm *TokenManager) LocalFetchToken(ctx context.Context) (err error) {
	// Generate an opaque identifier by hex-digesting random bytes.
	stateBuf := make([]byte, 32)
	if _, err = rand.Reader.Read(stateBuf); err != nil {
		return
	}
	oauth_state := hex.EncodeToString(stateBuf)
	authCodeURL := tm.config.AuthCodeURL(oauth_state, oauth2.AccessTypeOffline)
	fmt.Printf("Please go to the following link in your browser to generate an auth code:\n\t%s\n", authCodeURL)
	var code, state string

	fmt.Print("Authorization code:")
	fmt.Scanln(&code)
	fmt.Print("\nAuthorization state:")
	fmt.Scanln(&state)

	if oauth_state != state {
		return fmt.Errorf("states do not match")
	}

	token, err := tm.config.Exchange(ctx, code)
	if err != nil {
		return
	}
	fmt.Printf("Token Refresh Token: %s\n", token.RefreshToken)
	tm.token = token
	return
}

This is not producing Refresh tokens even with the oauth2.AccessTypeOffline option. In the past, this used to issue Refresh tokens.

According to the documentation on oauth2.AccessTypeOffline documentation:

	// AccessTypeOnline and AccessTypeOffline are options passed
	// to the Options.AuthCodeURL method. They modify the
	// "access_type" field that gets sent in the URL returned by
	// AuthCodeURL.
	//
	// Online is the default if neither is specified. If your
	// application needs to refresh access tokens when the user
	// is not present at the browser, then use offline. This will
	// result in your application obtaining **a refresh token the**
	// **first time your application exchanges an authorization**
	// **code for a user.**
	AccessTypeOnline  AuthCodeOption = SetAuthURLParam("access_type", "online")
	AccessTypeOffline AuthCodeOption = SetAuthURLParam("access_type", "offline")

Regards,

@redboxstudio
Copy link

Perhaps I encountered a similar problem, only I have slightly different conditions. I use keycloak and log in using the code, but in response I receive a token without refreshToken
image
however, there are examples where it is clear that refreshToken is provided
image

@redboxstudio
Copy link

I created a new client and it now has a button to enable token renewal

@YvanJAquino
Copy link
Author

It's worth noting that I need to prompt for consent - IE I need to do the ENTIRE flow.

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

No branches or pull requests

2 participants