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

feat: Longer lived api keys for cli #1935

Merged
merged 5 commits into from
Jun 1, 2022
Merged

feat: Longer lived api keys for cli #1935

merged 5 commits into from
Jun 1, 2022

Conversation

Emyrk
Copy link
Member

@Emyrk Emyrk commented May 31, 2022

#1269

What this does

Cli auth now lasts 1 week. Token refreshes use lifetime_seconds column on the api key to know how long to refresh

Comment on lines +31 to +34
CASE @lifetime_seconds::bigint
WHEN 0 THEN 86400
ELSE @lifetime_seconds::bigint
END
Copy link
Member Author

Choose a reason for hiding this comment

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

If the value is 0, we default to 24hrs

Comment on lines +661 to +668
lifeTime := time.Hour * 24 * 7
sessionToken, created := api.createAPIKey(rw, r, database.InsertAPIKeyParams{
UserID: user.ID,
LoginType: database.LoginTypePassword,
// All api generated keys will last 1 week. Browser login tokens have
// a shorter life.
ExpiresAt: database.Now().Add(lifeTime),
LifetimeSeconds: int64(lifeTime.Seconds()),
Copy link
Member Author

Choose a reason for hiding this comment

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

/login is still 24hrs. Creating api keys from the api (eg /cli-auth) is 1 week. Refreshes every hour as normal, so any activity every 7 days keeps it alive.

@Emyrk Emyrk marked this pull request as ready for review May 31, 2022 23:53
@Emyrk Emyrk requested a review from kylecarbs May 31, 2022 23:53
Comment on lines +31 to +34
CASE @lifetime_seconds::bigint
WHEN 0 THEN 86400
ELSE @lifetime_seconds::bigint
END
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't this be a default when creating the column rather than on insert?

Copy link
Member Author

Choose a reason for hiding this comment

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

It is a default on the column, but you cannot insert a nil value to the auto-generated code. So the default zero value in the insert code is 0. I want to treat that as a default of 24hrs. The column default was mainly for the migration to be happy.

The alternative is to put this default in the Go code, but we don't have a layer to gatekeep db functions. So I'd rather put this in the SQL where it's guaranteed to be checked.

Copy link
Contributor

Choose a reason for hiding this comment

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

If desired, we can fix this to use NULL to indicate a default value rather than 0 when the next version of sqlc is released, with support for sqlc.narg.

Copy link
Member Author

Choose a reason for hiding this comment

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

@dwahler yes. If narg or I also saw sqlc.arg(name, nullable) is supported, then we can do exactly that 👍. And use the column default.

Comment on lines +729 to +736
// Default expires at to now+lifetime, or just 24hrs if not set
if params.ExpiresAt.IsZero() {
if params.LifetimeSeconds != 0 {
params.ExpiresAt = database.Now().Add(time.Duration(params.LifetimeSeconds) * time.Second)
} else {
params.ExpiresAt = database.Now().Add(24 * time.Hour)
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Do you think we need an arbitrary amount of seconds for an API key to live for? I'm curious for @dwahler's thoughts.

Copy link
Member Author

Choose a reason for hiding this comment

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

We do if we want api keys to have different lifetimes. Currently the browser login api keys are valid for 24hrs. When we refresh them, we need to know how long to refresh them for (24hrs).

The cli keys will have a longer life (1 week). When you refresh, you need to know to add 1 week onto the expiresAt.

Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure where it falls on the spectrum of "needs", but I can definitely imagine this being useful, especially to enterprise users.

If the point of expiring keys is to mitigate risk, then you might want to make that tradeoff differently when the risk level is different. For instance, shorter lifetimes for keys that are stored on laptops (potentially prone to theft) or for admin users (where the consequences of key compromise are greater).

For now, I like specifying the lifetime as a request parameter, because it seems like the simplest way to expose this functionality. In the future it might make more sense for admins to be able to control the lifetimes with some kind of policy.

Copy link
Member Author

Choose a reason for hiding this comment

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

@dwahler It's not a configurable param from the api atm. There is just 2 endpoints (login and cli-auth) that make keys. But this backend does lead to it being easily configurable in the future.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, gotcha, I missed that params wasn't directly populated from the request.

Copy link
Member Author

Choose a reason for hiding this comment

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

@dwahler I didn't think it was necessary at this time, since it's 2 different routes.

Comment on lines +729 to +736
// Default expires at to now+lifetime, or just 24hrs if not set
if params.ExpiresAt.IsZero() {
if params.LifetimeSeconds != 0 {
params.ExpiresAt = database.Now().Add(time.Duration(params.LifetimeSeconds) * time.Second)
} else {
params.ExpiresAt = database.Now().Add(24 * time.Hour)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, gotcha, I missed that params wasn't directly populated from the request.

Comment on lines +31 to +34
CASE @lifetime_seconds::bigint
WHEN 0 THEN 86400
ELSE @lifetime_seconds::bigint
END
Copy link
Contributor

Choose a reason for hiding this comment

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

If desired, we can fix this to use NULL to indicate a default value rather than 0 when the next version of sqlc is released, with support for sqlc.narg.

@Emyrk Emyrk merged commit 913c0f5 into main Jun 1, 2022
@Emyrk Emyrk deleted the stevenmasley/long_api_keys branch June 1, 2022 19:58
kylecarbs pushed a commit that referenced this pull request Jun 10, 2022
* feat: Longer lived api keys for cli
* feat: Refresh tokens based on their lifetime set in the db
* test: Add unit test for refreshing
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

Successfully merging this pull request may close these issues.

None yet

3 participants