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

userinfo: expose http response information to library callers #248

Open
yanniszark opened this issue May 13, 2020 · 3 comments
Open

userinfo: expose http response information to library callers #248

yanniszark opened this issue May 13, 2020 · 3 comments

Comments

@yanniszark
Copy link

The current UserInfo() function makes an HTTP request and if something goes wrong, it returns a string error:

go-oidc/oidc.go

Lines 229 to 231 in 8d77155

if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("%s: %s", resp.Status, body)
}

I need to check the return code of the request to find out more about the reason it was denied (if the request was unauthorized, an internal error occurred at the server, etc.).
See also: https://www.rfc-editor.org/rfc/rfc6750.html#section-3.1

Would it be reasonable to define an error type for this kind of information?
The oauth2 package uses a RetrieveError for these cases:

// RetrieveError is the error returned when the token endpoint returns a
// non-2XX HTTP status code.
type RetrieveError struct {
	Response *http.Response
	// Body is the body that was consumed by reading Response.Body.
	// It may be truncated.
	Body []byte
}

cc @ericchiang

@ericchiang
Copy link
Collaborator

Is this to figure out when you need to rotate the token?

There's a lot of customization that request could use, and I don't know if we want to start going down the path of exposing knobs. Maybe make it easier to make the request yourself? e.g. we could export the user info URL to the Provider struct:

type Provider struct {
    UserInfoURL string
}

As well as have UserInfo implement UnmarshalJSON:

func (u *UserInfo) UnmarshalJSON(b []byte) error

Then you could customize your error handling:

req, err := http.NewRequest("GET", p.UserInfo, nil)
if err != nil {
	// ...
}
token.SetAuthHeader(req)

resp, err := myClient.Do(req)
if err != nil {
	// ...
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
	// your custom error handling
}
var u oidc.UserInfo
if err := json.NewDecoder(resp.Body).Decode(&u); err != nil {
	// ...
}

I'd like to avoid dealing with OAuth2 semantics as much as possible 😄 that's what golang.org/x/oauth2 is for.

@damz
Copy link

damz commented May 26, 2020

I just bumped into this. I wanted to use *Provider.UserInfo() to check a token provided externally. Unfortunately there is no way to distinguish between "any random server error" and "this token is invalid" in the current error scheme.

@yanniszark
Copy link
Author

@ericchiang thanks for taking the time such a detailed reply.
My thought was that the library could specifically enrich request-related errors with extra information, which would enable library users to do fine-grained error checking.
A RequestError could apply wherever a request is involved (discovery, token exchange, userinfo).
e.g., if the server returns 503, we might want to detect that and either retry the request or also return 503 to the user agent
In any case, both solutions are fine with me, please confirm what you think the best way to move forward is.

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

3 participants