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

[auth] Add multi-session support for auth pkg #240

Merged
merged 5 commits into from
Dec 22, 2023

Conversation

mikeland73
Copy link
Contributor

@mikeland73 mikeland73 commented Dec 20, 2023

Summary

Adds multi-session support to auth.

  • Every time a user logs in, we prepend the token to the token slice. We always dedup by subject, so if there's any existing token that matches that subject, we remove it.
  • Added GetSessions function. GetSessions returns refreshable tokens, instead of tokens. This allows the caller to inspect each token to find which one they want without having to refresh all. It also allows them to do useful stuff if only some tokens refresh successfully.
  • Session tokens are saved in a json file that contains a version.
  • Logout removes all tokens.
  • These changes are fully backwards compatible (which the exception that they will consider current users to be logged out, so they will require a single login on upgrade)

This will support allowing envsec to:

  • Initialize a project in any org you are logged in to.
  • Automatically use the correct token if you are logged in to multiple orgs and have projects in multiple orgs.

How was it tested?

envsec auth login

@mikeland73 mikeland73 requested review from loreto and savil December 20, 2023 22:02
Copy link
Contributor

@savil savil left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great - one question about whether we want to always prepend to the start of the tokens list for every write, or whether it makes sense to distinguish login from refresh writes?

pkg/auth/auth.go Outdated
}
}

return tokens, errors.Join(refreshErrors...)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the current design, we return tokens as well as a joined-error. How is the caller expected to handle these tokens if the error is non-nil?

Is it something like:

tokens, err := c.GetSessions()
if err != nil {
     fmt.Println("WARNING: some tokens failed to refresh")
     // optionally, internally log `err` to sentry
}
for _, tok := range tokens {
    if tok.IsValid() {
            // do something useful with tok
     } 
}

?

An alternate design would be:
callers can read both tokens[i] amd errors[i] and see the reason for why that token is possibly invalid. But i'm not sure how this API is intended to be used, so having trouble discerning which design is better.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea behind this API is to allow the caller to still display useful into even if error. For example, you have 3 tokens, 2 work and one failed to refresh. The caller wants to show what orgs are available. In that case, it can display:

  • org 1
  • org 2
  • org 3 (requires re-login)

instead of just erroring out and requiring full login no matter what.

returning a slice of tokens and a slice or errors would be very un-go'ish. Another alternative is to return something like:

type TokenSource interface {
	Token() (*Token, error)
}

(this interface is actually part of oauth2 package)

type Store struct {
rootDir string
}

type storeData struct {
Version string `json:"version"`
Tokens []*session.Token `json:"tokens"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice to comment here that the order matters: tokens in front are given priority, and a new token is pre-pended to the existing list

pkg/auth/auth.go Outdated
// expired tokens, and returns an error if any tokens are unable to be
// refreshed. If there are errors, it still returns all tokens, some of which
// may be expired.
func (c *Client) GetSessions(ctx context.Context) ([]*session.Token, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where is this used?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not currently used, but the plan is for envsec to use it to show what orgs you can use to initialize a project.

Comment on lines +114 to +120
tokens := []*session.Token{tok}
for _, t := range sd.Tokens {
if t.IDClaims().Subject != tok.IDClaims().Subject {
tokens = append(tokens, t)
}
}
sd.Tokens = tokens
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The order seems to matter and have product implications in terms of what is returned from ReadToken. Given that:

Can we distinguish login-writes from refresh-writes?

I can understand wanting to move login-write-tokens to the front for priority. However, its unclear to me that refresh-write-tokens should move to the front, or whether they should be kept in their current position

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will do, this is a bug in my implementation. Refreshing a token should not change the order, only logins should.

Copy link
Contributor

@savil savil left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spoke offline - will keep refresh writes in-place, approving pre-emptively

@mikeland73 mikeland73 merged commit 87676e8 into main Dec 22, 2023
1 check passed
@mikeland73 mikeland73 deleted the landau/allow-auth-multi-user branch December 22, 2023 23:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants