@@ -18,6 +18,7 @@ import (
1818"github.com/coder/coder/v2/coderd/database/dbtime"
1919"github.com/coder/coder/v2/coderd/httpapi"
2020"github.com/coder/coder/v2/coderd/httpmw"
21+ "github.com/coder/coder/v2/coderd/rbac"
2122"github.com/coder/coder/v2/coderd/rbac/policy"
2223"github.com/coder/coder/v2/coderd/telemetry"
2324"github.com/coder/coder/v2/codersdk"
@@ -75,7 +76,7 @@ func (api *API) postToken(rw http.ResponseWriter, r *http.Request) {
7576}
7677
7778if createToken .Lifetime != 0 {
78- err := api .validateAPIKeyLifetime (createToken .Lifetime )
79+ err := api .validateAPIKeyLifetime (ctx , user . ID , createToken .Lifetime )
7980if err != nil {
8081httpapi .Write (ctx ,rw ,http .StatusBadRequest , codersdk.Response {
8182Message :"Failed to validate create API key request." ,
@@ -338,35 +339,69 @@ func (api *API) deleteAPIKey(rw http.ResponseWriter, r *http.Request) {
338339// @Success 200 {object} codersdk.TokenConfig
339340// @Router /users/{user}/keys/tokens/tokenconfig [get]
340341func (api * API )tokenConfig (rw http.ResponseWriter ,r * http.Request ) {
341- values ,err := api .DeploymentValues .WithoutSecrets ()
342+ user := httpmw .UserParam (r )
343+ maxLifetime ,err := api .getMaxTokenLifetime (r .Context (),user .ID )
342344if err != nil {
343- httpapi .InternalServerError (rw ,err )
345+ httpapi .Write (r .Context (),rw ,http .StatusInternalServerError , codersdk.Response {
346+ Message :"Failed to get token configuration." ,
347+ Detail :err .Error (),
348+ })
344349return
345350}
346351
347352httpapi .Write (
348353r .Context (),rw ,http .StatusOK ,
349354codersdk.TokenConfig {
350- MaxTokenLifetime :values . Sessions . MaximumTokenDuration . Value () ,
355+ MaxTokenLifetime :maxLifetime ,
351356},
352357)
353358}
354359
355- func (api * API )validateAPIKeyLifetime (lifetime time.Duration )error {
360+ func (api * API )validateAPIKeyLifetime (ctx context. Context , userID uuid. UUID , lifetime time.Duration )error {
356361if lifetime <= 0 {
357362return xerrors .New ("lifetime must be positive number greater than 0" )
358363}
359364
360- if lifetime > api .DeploymentValues .Sessions .MaximumTokenDuration .Value () {
365+ maxLifetime ,err := api .getMaxTokenLifetime (ctx ,userID )
366+ if err != nil {
367+ return xerrors .Errorf ("failed to get max token lifetime: %w" ,err )
368+ }
369+
370+ if lifetime > maxLifetime {
361371return xerrors .Errorf (
362372"lifetime must be less than %v" ,
363- api . DeploymentValues . Sessions . MaximumTokenDuration ,
373+ maxLifetime ,
364374)
365375}
366376
367377return nil
368378}
369379
380+ // getMaxTokenLifetime returns the maximum allowed token lifetime for a user.
381+ // It distinguishes between regular users and owners.
382+ func (api * API )getMaxTokenLifetime (ctx context.Context ,userID uuid.UUID ) (time.Duration ,error ) {
383+ subject ,_ ,err := httpmw .UserRBACSubject (ctx ,api .Database ,userID ,rbac .ScopeAll )
384+ if err != nil {
385+ return 0 ,xerrors .Errorf ("failed to get user rbac subject: %w" ,err )
386+ }
387+
388+ roles ,err := subject .Roles .Expand ()
389+ if err != nil {
390+ return 0 ,xerrors .Errorf ("failed to expand user roles: %w" ,err )
391+ }
392+
393+ maxLifetime := api .DeploymentValues .Sessions .MaximumTokenDuration .Value ()
394+ for _ ,role := range roles {
395+ if role .Identifier .Name == codersdk .RoleOwner {
396+ // Owners have a longer max lifetime.
397+ maxLifetime = api .DeploymentValues .Sessions .MaximumAdminTokenDuration .Value ()
398+ break
399+ }
400+ }
401+
402+ return maxLifetime ,nil
403+ }
404+
370405func (api * API )createAPIKey (ctx context.Context ,params apikey.CreateParams ) (* http.Cookie ,* database.APIKey ,error ) {
371406key ,sessionToken ,err := apikey .Generate (params )
372407if err != nil {