- Notifications
You must be signed in to change notification settings - Fork928
feat: Longer lived api keys for cli#1935
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Changes fromall commits
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.
Uh oh!
There was an error while loading.Please reload this page.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
ALTER TABLE api_keys DROP COLUMN lifetime_seconds; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
-- Default lifetime is 24hours. | ||
ALTER TABLE api_keys ADD COLUMN lifetime_seconds bigint default 86400 NOT NULL; |
Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.
Uh oh!
There was an error while loading.Please reload this page.
Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.
Uh oh!
There was an error while loading.Please reload this page.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -12,6 +12,7 @@ LIMIT | ||
INSERT INTO | ||
api_keys ( | ||
id, | ||
lifetime_seconds, | ||
hashed_secret, | ||
user_id, | ||
last_used, | ||
@@ -25,7 +26,13 @@ INSERT INTO | ||
oauth_expiry | ||
) | ||
VALUES | ||
(@id, | ||
-- If the lifetime is set to 0, default to 24hrs | ||
CASE @lifetime_seconds::bigint | ||
WHEN 0 THEN 86400 | ||
ELSE @lifetime_seconds::bigint | ||
END | ||
Comment on lines +31 to +34 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. If the value is 0, we default to 24hrs Comment on lines +31 to +34 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. It is a default on the column, but you cannot insert a 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. If desired, we can fix this to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. @dwahler yes. If | ||
, @hashed_secret, @user_id, @last_used, @expires_at, @created_at, @updated_at, @login_type, @oauth_access_token, @oauth_refresh_token, @oauth_id_token, @oauth_expiry) RETURNING *; | ||
-- name: UpdateAPIKeyByID :exec | ||
UPDATE | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -658,9 +658,14 @@ func (api *API) postAPIKey(rw http.ResponseWriter, r *http.Request) { | ||
return | ||
} | ||
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()), | ||
Comment on lines +661 to +668 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more.
| ||
}) | ||
if !created { | ||
return | ||
@@ -721,10 +726,21 @@ func (api *API) createAPIKey(rw http.ResponseWriter, r *http.Request, params dat | ||
} | ||
hashed := sha256.Sum256([]byte(keySecret)) | ||
// 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) | ||
} | ||
} | ||
Comment on lines +729 to +736 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Ah, gotcha, I missed that There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. | ||
_, err = api.Database.InsertAPIKey(r.Context(), database.InsertAPIKeyParams{ | ||
ID: keyID, | ||
UserID: params.UserID, | ||
LifetimeSeconds: params.LifetimeSeconds, | ||
// Make sure in UTC time for common time zone | ||
ExpiresAt: params.ExpiresAt.UTC(), | ||
CreatedAt: database.Now(), | ||
UpdatedAt: database.Now(), | ||
HashedSecret: hashed[:], | ||