chore: merge apikey/token session config values (#12817)

* chore: merge apikey/token session config values

There is a confusing difference between an apikey and a token. This
difference leaks into our configs. This change does not resolve the
difference. It only groups the config values to try and manage any
bloat that occurs from adding more similar config values
This commit is contained in:
Steven Masley 2024-04-10 10:34:49 -05:00 committed by GitHub
parent 4dc293d930
commit 838e8df5be
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 157 additions and 82 deletions

28
coderd/apidoc/docs.go generated
View File

@ -9296,9 +9296,6 @@ const docTemplate = `{
"disable_path_apps": {
"type": "boolean"
},
"disable_session_expiry_refresh": {
"type": "boolean"
},
"docs_url": {
"$ref": "#/definitions/serpent.URL"
},
@ -9336,12 +9333,6 @@ const docTemplate = `{
"logging": {
"$ref": "#/definitions/codersdk.LoggingConfig"
},
"max_session_expiry": {
"type": "integer"
},
"max_token_lifetime": {
"type": "integer"
},
"metrics_cache_refresh_interval": {
"type": "integer"
},
@ -9393,6 +9384,9 @@ const docTemplate = `{
"secure_auth_cookie": {
"type": "boolean"
},
"session_lifetime": {
"$ref": "#/definitions/codersdk.SessionLifetime"
},
"ssh_keygen_algorithm": {
"type": "string"
},
@ -11085,6 +11079,22 @@ const docTemplate = `{
}
}
},
"codersdk.SessionLifetime": {
"type": "object",
"properties": {
"default_duration": {
"description": "DefaultDuration is for api keys, not tokens.",
"type": "integer"
},
"disable_expiry_refresh": {
"description": "DisableExpiryRefresh will disable automatically refreshing api\nkeys when they are used from the api. This means the api key lifetime at\ncreation is the lifetime of the api key.",
"type": "boolean"
},
"max_token_lifetime": {
"type": "integer"
}
}
},
"codersdk.SupportConfig": {
"type": "object",
"properties": {

View File

@ -8301,9 +8301,6 @@
"disable_path_apps": {
"type": "boolean"
},
"disable_session_expiry_refresh": {
"type": "boolean"
},
"docs_url": {
"$ref": "#/definitions/serpent.URL"
},
@ -8341,12 +8338,6 @@
"logging": {
"$ref": "#/definitions/codersdk.LoggingConfig"
},
"max_session_expiry": {
"type": "integer"
},
"max_token_lifetime": {
"type": "integer"
},
"metrics_cache_refresh_interval": {
"type": "integer"
},
@ -8398,6 +8389,9 @@
"secure_auth_cookie": {
"type": "boolean"
},
"session_lifetime": {
"$ref": "#/definitions/codersdk.SessionLifetime"
},
"ssh_keygen_algorithm": {
"type": "string"
},
@ -9987,6 +9981,22 @@
}
}
},
"codersdk.SessionLifetime": {
"type": "object",
"properties": {
"default_duration": {
"description": "DefaultDuration is for api keys, not tokens.",
"type": "integer"
},
"disable_expiry_refresh": {
"description": "DisableExpiryRefresh will disable automatically refreshing api\nkeys when they are used from the api. This means the api key lifetime at\ncreation is the lifetime of the api key.",
"type": "boolean"
},
"max_token_lifetime": {
"type": "integer"
}
}
},
"codersdk.SupportConfig": {
"type": "object",
"properties": {

View File

@ -84,7 +84,7 @@ func (api *API) postToken(rw http.ResponseWriter, r *http.Request) {
cookie, key, err := api.createAPIKey(ctx, apikey.CreateParams{
UserID: user.ID,
LoginType: database.LoginTypeToken,
DefaultLifetime: api.DeploymentValues.SessionDuration.Value(),
DefaultLifetime: api.DeploymentValues.Sessions.DefaultDuration.Value(),
ExpiresAt: dbtime.Now().Add(lifeTime),
Scope: scope,
LifetimeSeconds: int64(lifeTime.Seconds()),
@ -128,7 +128,7 @@ func (api *API) postAPIKey(rw http.ResponseWriter, r *http.Request) {
lifeTime := time.Hour * 24 * 7
cookie, _, err := api.createAPIKey(ctx, apikey.CreateParams{
UserID: user.ID,
DefaultLifetime: api.DeploymentValues.SessionDuration.Value(),
DefaultLifetime: api.DeploymentValues.Sessions.DefaultDuration.Value(),
LoginType: database.LoginTypePassword,
RemoteAddr: r.RemoteAddr,
// All api generated keys will last 1 week. Browser login tokens have
@ -354,7 +354,7 @@ func (api *API) tokenConfig(rw http.ResponseWriter, r *http.Request) {
httpapi.Write(
r.Context(), rw, http.StatusOK,
codersdk.TokenConfig{
MaxTokenLifetime: values.MaxTokenLifetime.Value(),
MaxTokenLifetime: values.Sessions.MaximumTokenDuration.Value(),
},
)
}
@ -364,10 +364,10 @@ func (api *API) validateAPIKeyLifetime(lifetime time.Duration) error {
return xerrors.New("lifetime must be positive number greater than 0")
}
if lifetime > api.DeploymentValues.MaxTokenLifetime.Value() {
if lifetime > api.DeploymentValues.Sessions.MaximumTokenDuration.Value() {
return xerrors.Errorf(
"lifetime must be less than %v",
api.DeploymentValues.MaxTokenLifetime,
api.DeploymentValues.Sessions.MaximumTokenDuration,
)
}

View File

@ -125,7 +125,7 @@ func TestTokenUserSetMaxLifetime(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()
dc := coderdtest.DeploymentValues(t)
dc.MaxTokenLifetime = serpent.Duration(time.Hour * 24 * 7)
dc.Sessions.MaximumTokenDuration = serpent.Duration(time.Hour * 24 * 7)
client := coderdtest.New(t, &coderdtest.Options{
DeploymentValues: dc,
})
@ -165,7 +165,7 @@ func TestSessionExpiry(t *testing.T) {
//
// We don't support updating the deployment config after startup, but for
// this test it works because we don't copy the value (and we use pointers).
dc.SessionDuration = serpent.Duration(time.Second)
dc.Sessions.DefaultDuration = serpent.Duration(time.Second)
userClient, _ := coderdtest.CreateAnotherUser(t, adminClient, adminUser.OrganizationID)
@ -174,8 +174,8 @@ func TestSessionExpiry(t *testing.T) {
apiKey, err := db.GetAPIKeyByID(ctx, strings.Split(token, "-")[0])
require.NoError(t, err)
require.EqualValues(t, dc.SessionDuration.Value().Seconds(), apiKey.LifetimeSeconds)
require.WithinDuration(t, apiKey.CreatedAt.Add(dc.SessionDuration.Value()), apiKey.ExpiresAt, 2*time.Second)
require.EqualValues(t, dc.Sessions.DefaultDuration.Value().Seconds(), apiKey.LifetimeSeconds)
require.WithinDuration(t, apiKey.CreatedAt.Add(dc.Sessions.DefaultDuration.Value()), apiKey.ExpiresAt, 2*time.Second)
// Update the session token to be expired so we can test that it is
// rejected for extra points.

View File

@ -566,7 +566,7 @@ func New(options *Options) *API {
DB: options.Database,
OAuth2Configs: oauthConfigs,
RedirectToLogin: false,
DisableSessionExpiryRefresh: options.DeploymentValues.DisableSessionExpiryRefresh.Value(),
DisableSessionExpiryRefresh: options.DeploymentValues.Sessions.DisableExpiryRefresh.Value(),
Optional: false,
SessionTokenFunc: nil, // Default behavior
PostAuthAdditionalHeadersFunc: options.PostAuthAdditionalHeadersFunc,
@ -576,7 +576,7 @@ func New(options *Options) *API {
DB: options.Database,
OAuth2Configs: oauthConfigs,
RedirectToLogin: true,
DisableSessionExpiryRefresh: options.DeploymentValues.DisableSessionExpiryRefresh.Value(),
DisableSessionExpiryRefresh: options.DeploymentValues.Sessions.DisableExpiryRefresh.Value(),
Optional: false,
SessionTokenFunc: nil, // Default behavior
PostAuthAdditionalHeadersFunc: options.PostAuthAdditionalHeadersFunc,
@ -586,7 +586,7 @@ func New(options *Options) *API {
DB: options.Database,
OAuth2Configs: oauthConfigs,
RedirectToLogin: false,
DisableSessionExpiryRefresh: options.DeploymentValues.DisableSessionExpiryRefresh.Value(),
DisableSessionExpiryRefresh: options.DeploymentValues.Sessions.DisableExpiryRefresh.Value(),
Optional: true,
SessionTokenFunc: nil, // Default behavior
PostAuthAdditionalHeadersFunc: options.PostAuthAdditionalHeadersFunc,

View File

@ -7,7 +7,6 @@ import (
"fmt"
"net/http"
"net/url"
"time"
"github.com/google/uuid"
"golang.org/x/oauth2"
@ -75,7 +74,11 @@ func extractTokenParams(r *http.Request, callbackURL *url.URL) (tokenParams, []c
return params, nil, nil
}
func Tokens(db database.Store, defaultLifetime time.Duration) http.HandlerFunc {
// Tokens
// TODO: the sessions lifetime config passed is for coder api tokens.
// Should there be a separate config for oauth2 tokens? They are related,
// but they are not the same.
func Tokens(db database.Store, lifetimes codersdk.SessionLifetime) http.HandlerFunc {
return func(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
app := httpmw.OAuth2ProviderApp(r)
@ -104,9 +107,9 @@ func Tokens(db database.Store, defaultLifetime time.Duration) http.HandlerFunc {
switch params.grantType {
// TODO: Client creds, device code.
case codersdk.OAuth2ProviderGrantTypeRefreshToken:
token, err = refreshTokenGrant(ctx, db, app, defaultLifetime, params)
token, err = refreshTokenGrant(ctx, db, app, lifetimes, params)
case codersdk.OAuth2ProviderGrantTypeAuthorizationCode:
token, err = authorizationCodeGrant(ctx, db, app, defaultLifetime, params)
token, err = authorizationCodeGrant(ctx, db, app, lifetimes, params)
default:
// Grant types are validated by the parser, so getting through here means
// the developer added a type but forgot to add a case here.
@ -137,7 +140,7 @@ func Tokens(db database.Store, defaultLifetime time.Duration) http.HandlerFunc {
}
}
func authorizationCodeGrant(ctx context.Context, db database.Store, app database.OAuth2ProviderApp, defaultLifetime time.Duration, params tokenParams) (oauth2.Token, error) {
func authorizationCodeGrant(ctx context.Context, db database.Store, app database.OAuth2ProviderApp, lifetimes codersdk.SessionLifetime, params tokenParams) (oauth2.Token, error) {
// Validate the client secret.
secret, err := parseSecret(params.clientSecret)
if err != nil {
@ -195,11 +198,9 @@ func authorizationCodeGrant(ctx context.Context, db database.Store, app database
// TODO: We are ignoring scopes for now.
tokenName := fmt.Sprintf("%s_%s_oauth_session_token", dbCode.UserID, app.ID)
key, sessionToken, err := apikey.Generate(apikey.CreateParams{
UserID: dbCode.UserID,
LoginType: database.LoginTypeOAuth2ProviderApp,
// TODO: This is just the lifetime for api keys, maybe have its own config
// settings. #11693
DefaultLifetime: defaultLifetime,
UserID: dbCode.UserID,
LoginType: database.LoginTypeOAuth2ProviderApp,
DefaultLifetime: lifetimes.DefaultDuration.Value(),
// For now, we allow only one token per app and user at a time.
TokenName: tokenName,
})
@ -271,7 +272,7 @@ func authorizationCodeGrant(ctx context.Context, db database.Store, app database
}, nil
}
func refreshTokenGrant(ctx context.Context, db database.Store, app database.OAuth2ProviderApp, defaultLifetime time.Duration, params tokenParams) (oauth2.Token, error) {
func refreshTokenGrant(ctx context.Context, db database.Store, app database.OAuth2ProviderApp, lifetimes codersdk.SessionLifetime, params tokenParams) (oauth2.Token, error) {
// Validate the token.
token, err := parseSecret(params.refreshToken)
if err != nil {
@ -326,11 +327,9 @@ func refreshTokenGrant(ctx context.Context, db database.Store, app database.OAut
// TODO: We are ignoring scopes for now.
tokenName := fmt.Sprintf("%s_%s_oauth_session_token", prevKey.UserID, app.ID)
key, sessionToken, err := apikey.Generate(apikey.CreateParams{
UserID: prevKey.UserID,
LoginType: database.LoginTypeOAuth2ProviderApp,
// TODO: This is just the lifetime for api keys, maybe have its own config
// settings. #11693
DefaultLifetime: defaultLifetime,
UserID: prevKey.UserID,
LoginType: database.LoginTypeOAuth2ProviderApp,
DefaultLifetime: lifetimes.DefaultDuration.Value(),
// For now, we allow only one token per app and user at a time.
TokenName: tokenName,
})

View File

@ -354,7 +354,7 @@ func (api *API) getOAuth2ProviderAppAuthorize() http.HandlerFunc {
// @Success 200 {object} oauth2.Token
// @Router /oauth2/tokens [post]
func (api *API) postOAuth2ProviderAppToken() http.HandlerFunc {
return identityprovider.Tokens(api.Database, api.DeploymentValues.SessionDuration.Value())
return identityprovider.Tokens(api.Database, api.DeploymentValues.Sessions)
}
// @Summary Delete OAuth2 application tokens.

View File

@ -1737,9 +1737,9 @@ func (s *server) regenerateSessionToken(ctx context.Context, user database.User,
newkey, sessionToken, err := apikey.Generate(apikey.CreateParams{
UserID: user.ID,
LoginType: user.LoginType,
DefaultLifetime: s.DeploymentValues.SessionDuration.Value(),
TokenName: workspaceSessionTokenName(workspace),
LifetimeSeconds: int64(s.DeploymentValues.MaxTokenLifetime.Value().Seconds()),
DefaultLifetime: s.DeploymentValues.Sessions.DefaultDuration.Value(),
LifetimeSeconds: int64(s.DeploymentValues.Sessions.MaximumTokenDuration.Value().Seconds()),
})
if err != nil {
return "", xerrors.Errorf("generate API key: %w", err)

View File

@ -166,7 +166,11 @@ func TestAcquireJob(t *testing.T) {
// Set the max session token lifetime so we can assert we
// create an API key with an expiration within the bounds of the
// deployment config.
dv := &codersdk.DeploymentValues{MaxTokenLifetime: serpent.Duration(time.Hour)}
dv := &codersdk.DeploymentValues{
Sessions: codersdk.SessionLifetime{
MaximumTokenDuration: serpent.Duration(time.Hour),
},
}
gitAuthProvider := &sdkproto.ExternalAuthProviderResource{
Id: "github",
}
@ -319,8 +323,8 @@ func TestAcquireJob(t *testing.T) {
require.Len(t, toks, 2, "invalid api key")
key, err := db.GetAPIKeyByID(ctx, toks[0])
require.NoError(t, err)
require.Equal(t, int64(dv.MaxTokenLifetime.Value().Seconds()), key.LifetimeSeconds)
require.WithinDuration(t, time.Now().Add(dv.MaxTokenLifetime.Value()), key.ExpiresAt, time.Minute)
require.Equal(t, int64(dv.Sessions.MaximumTokenDuration.Value().Seconds()), key.LifetimeSeconds)
require.WithinDuration(t, time.Now().Add(dv.Sessions.MaximumTokenDuration.Value()), key.ExpiresAt, time.Minute)
want, err := json.Marshal(&proto.AcquiredJob_WorkspaceBuild_{
WorkspaceBuild: &proto.AcquiredJob_WorkspaceBuild{

View File

@ -252,7 +252,7 @@ func (api *API) postLogin(rw http.ResponseWriter, r *http.Request) {
UserID: user.ID,
LoginType: database.LoginTypePassword,
RemoteAddr: r.RemoteAddr,
DefaultLifetime: api.DeploymentValues.SessionDuration.Value(),
DefaultLifetime: api.DeploymentValues.Sessions.DefaultDuration.Value(),
})
if err != nil {
logger.Error(ctx, "unable to create API key", slog.Error(err))
@ -1612,7 +1612,7 @@ func (api *API) oauthLogin(r *http.Request, params *oauthLoginParams) ([]*http.C
cookie, newKey, err := api.createAPIKey(dbauthz.AsSystemRestricted(ctx), apikey.CreateParams{
UserID: user.ID,
LoginType: params.LoginType,
DefaultLifetime: api.DeploymentValues.SessionDuration.Value(),
DefaultLifetime: api.DeploymentValues.Sessions.DefaultDuration.Value(),
RemoteAddr: r.RemoteAddr,
})
if err != nil {

View File

@ -102,14 +102,14 @@ func (api *API) workspaceApplicationAuth(rw http.ResponseWriter, r *http.Request
// the current session.
exp := apiKey.ExpiresAt
lifetimeSeconds := apiKey.LifetimeSeconds
if exp.IsZero() || time.Until(exp) > api.DeploymentValues.SessionDuration.Value() {
exp = dbtime.Now().Add(api.DeploymentValues.SessionDuration.Value())
lifetimeSeconds = int64(api.DeploymentValues.SessionDuration.Value().Seconds())
if exp.IsZero() || time.Until(exp) > api.DeploymentValues.Sessions.DefaultDuration.Value() {
exp = dbtime.Now().Add(api.DeploymentValues.Sessions.DefaultDuration.Value())
lifetimeSeconds = int64(api.DeploymentValues.Sessions.DefaultDuration.Value().Seconds())
}
cookie, _, err := api.createAPIKey(ctx, apikey.CreateParams{
UserID: apiKey.UserID,
LoginType: database.LoginTypePassword,
DefaultLifetime: api.DeploymentValues.SessionDuration.Value(),
DefaultLifetime: api.DeploymentValues.Sessions.DefaultDuration.Value(),
ExpiresAt: exp,
LifetimeSeconds: lifetimeSeconds,
Scope: database.APIKeyScopeApplicationConnect,

View File

@ -85,7 +85,7 @@ func (p *DBTokenProvider) Issue(ctx context.Context, rw http.ResponseWriter, r *
DB: p.Database,
OAuth2Configs: p.OAuth2Configs,
RedirectToLogin: false,
DisableSessionExpiryRefresh: p.DeploymentValues.DisableSessionExpiryRefresh.Value(),
DisableSessionExpiryRefresh: p.DeploymentValues.Sessions.DisableExpiryRefresh.Value(),
// Optional is true to allow for public apps. If the authorization check
// (later on) fails and the user is not authenticated, they will be
// redirected to the login page or app auth endpoint using code below.

View File

@ -182,13 +182,11 @@ type DeploymentValues struct {
RateLimit RateLimitConfig `json:"rate_limit,omitempty" typescript:",notnull"`
Experiments serpent.StringArray `json:"experiments,omitempty" typescript:",notnull"`
UpdateCheck serpent.Bool `json:"update_check,omitempty" typescript:",notnull"`
MaxTokenLifetime serpent.Duration `json:"max_token_lifetime,omitempty" typescript:",notnull"`
Swagger SwaggerConfig `json:"swagger,omitempty" typescript:",notnull"`
Logging LoggingConfig `json:"logging,omitempty" typescript:",notnull"`
Dangerous DangerousConfig `json:"dangerous,omitempty" typescript:",notnull"`
DisablePathApps serpent.Bool `json:"disable_path_apps,omitempty" typescript:",notnull"`
SessionDuration serpent.Duration `json:"max_session_expiry,omitempty" typescript:",notnull"`
DisableSessionExpiryRefresh serpent.Bool `json:"disable_session_expiry_refresh,omitempty" typescript:",notnull"`
Sessions SessionLifetime `json:"session_lifetime,omitempty" typescript:",notnull"`
DisablePasswordAuth serpent.Bool `json:"disable_password_auth,omitempty" typescript:",notnull"`
Support SupportConfig `json:"support,omitempty" typescript:",notnull"`
ExternalAuthConfigs serpent.Struct[[]ExternalAuthConfig] `json:"external_auth,omitempty" typescript:",notnull"`
@ -244,6 +242,33 @@ func ParseSSHConfigOption(opt string) (key string, value string, err error) {
return opt[:idx], opt[idx+1:], nil
}
// SessionLifetime refers to "sessions" authenticating into Coderd. Coder has
// multiple different session types: api keys, tokens, workspace app tokens,
// agent tokens, etc. This configuration struct should be used to group all
// settings referring to any of these session lifetime controls.
// TODO: These config options were created back when coder only had api keys.
// Today, the config is ambigously used for all of them. For example:
// - cli based api keys ignore all settings
// - login uses the default lifetime, not the MaximumTokenDuration
// - Tokens use the Default & MaximumTokenDuration
// - ... etc ...
// The rational behind each decision is undocumented. The naming behind these
// config options is also confusing without any clear documentation.
// 'CreateAPIKey' is used to make all sessions, and it's parameters are just
// 'LifetimeSeconds' and 'DefaultLifetime'. Which does not directly correlate to
// the config options here.
type SessionLifetime struct {
// DisableExpiryRefresh will disable automatically refreshing api
// keys when they are used from the api. This means the api key lifetime at
// creation is the lifetime of the api key.
DisableExpiryRefresh serpent.Bool `json:"disable_expiry_refresh,omitempty" typescript:",notnull"`
// DefaultDuration is for api keys, not tokens.
DefaultDuration serpent.Duration `json:"default_duration" typescript:",notnull"`
MaximumTokenDuration serpent.Duration `json:"max_token_lifetime,omitempty" typescript:",notnull"`
}
type DERP struct {
Server DERPServerConfig `json:"server" typescript:",notnull"`
Config DERPConfig `json:"config" typescript:",notnull"`
@ -1579,7 +1604,7 @@ when required by your organization's security policy.`,
// We have to add in the 25 leap days for the frontend to show the
// "100 years" correctly.
Default: ((100 * 365 * time.Hour * 24) + (25 * time.Hour * 24)).String(),
Value: &c.MaxTokenLifetime,
Value: &c.Sessions.MaximumTokenDuration,
Group: &deploymentGroupNetworkingHTTP,
YAML: "maxTokenLifetime",
Annotations: serpent.Annotations{}.Mark(annotationFormatDuration, "true"),
@ -1773,7 +1798,7 @@ when required by your organization's security policy.`,
Flag: "session-duration",
Env: "CODER_SESSION_DURATION",
Default: (24 * time.Hour).String(),
Value: &c.SessionDuration,
Value: &c.Sessions.DefaultDuration,
Group: &deploymentGroupNetworkingHTTP,
YAML: "sessionDuration",
Annotations: serpent.Annotations{}.Mark(annotationFormatDuration, "true"),
@ -1784,7 +1809,7 @@ when required by your organization's security policy.`,
Flag: "disable-session-expiry-refresh",
Env: "CODER_DISABLE_SESSION_EXPIRY_REFRESH",
Value: &c.DisableSessionExpiryRefresh,
Value: &c.Sessions.DisableExpiryRefresh,
Group: &deploymentGroupNetworkingHTTP,
YAML: "disableSessionExpiryRefresh",
},

8
docs/api/general.md generated
View File

@ -200,7 +200,6 @@ curl -X GET http://coder-server:8080/api/v2/deployment/config \
"disable_owner_workspace_exec": true,
"disable_password_auth": true,
"disable_path_apps": true,
"disable_session_expiry_refresh": true,
"docs_url": {
"forceQuery": true,
"fragment": "string",
@ -252,8 +251,6 @@ curl -X GET http://coder-server:8080/api/v2/deployment/config \
"log_filter": ["string"],
"stackdriver": "string"
},
"max_session_expiry": 0,
"max_token_lifetime": 0,
"metrics_cache_refresh_interval": 0,
"oauth2": {
"github": {
@ -341,6 +338,11 @@ curl -X GET http://coder-server:8080/api/v2/deployment/config \
"redirect_to_access_url": true,
"scim_api_key": "string",
"secure_auth_cookie": true,
"session_lifetime": {
"default_duration": 0,
"disable_expiry_refresh": true,
"max_token_lifetime": 0
},
"ssh_keygen_algorithm": "string",
"strict_transport_security": 0,
"strict_transport_security_options": ["string"],

38
docs/api/schemas.md generated
View File

@ -1925,7 +1925,6 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
"disable_owner_workspace_exec": true,
"disable_password_auth": true,
"disable_path_apps": true,
"disable_session_expiry_refresh": true,
"docs_url": {
"forceQuery": true,
"fragment": "string",
@ -1977,8 +1976,6 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
"log_filter": ["string"],
"stackdriver": "string"
},
"max_session_expiry": 0,
"max_token_lifetime": 0,
"metrics_cache_refresh_interval": 0,
"oauth2": {
"github": {
@ -2066,6 +2063,11 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
"redirect_to_access_url": true,
"scim_api_key": "string",
"secure_auth_cookie": true,
"session_lifetime": {
"default_duration": 0,
"disable_expiry_refresh": true,
"max_token_lifetime": 0
},
"ssh_keygen_algorithm": "string",
"strict_transport_security": 0,
"strict_transport_security_options": ["string"],
@ -2295,7 +2297,6 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
"disable_owner_workspace_exec": true,
"disable_password_auth": true,
"disable_path_apps": true,
"disable_session_expiry_refresh": true,
"docs_url": {
"forceQuery": true,
"fragment": "string",
@ -2347,8 +2348,6 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
"log_filter": ["string"],
"stackdriver": "string"
},
"max_session_expiry": 0,
"max_token_lifetime": 0,
"metrics_cache_refresh_interval": 0,
"oauth2": {
"github": {
@ -2436,6 +2435,11 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
"redirect_to_access_url": true,
"scim_api_key": "string",
"secure_auth_cookie": true,
"session_lifetime": {
"default_duration": 0,
"disable_expiry_refresh": true,
"max_token_lifetime": 0
},
"ssh_keygen_algorithm": "string",
"strict_transport_security": 0,
"strict_transport_security_options": ["string"],
@ -2526,7 +2530,6 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
| `disable_owner_workspace_exec` | boolean | false | | |
| `disable_password_auth` | boolean | false | | |
| `disable_path_apps` | boolean | false | | |
| `disable_session_expiry_refresh` | boolean | false | | |
| `docs_url` | [serpent.URL](#serpenturl) | false | | |
| `enable_terraform_debug_mode` | boolean | false | | |
| `experiments` | array of string | false | | |
@ -2537,8 +2540,6 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
| `in_memory_database` | boolean | false | | |
| `job_hang_detector_interval` | integer | false | | |
| `logging` | [codersdk.LoggingConfig](#codersdkloggingconfig) | false | | |
| `max_session_expiry` | integer | false | | |
| `max_token_lifetime` | integer | false | | |
| `metrics_cache_refresh_interval` | integer | false | | |
| `oauth2` | [codersdk.OAuth2Config](#codersdkoauth2config) | false | | |
| `oidc` | [codersdk.OIDCConfig](#codersdkoidcconfig) | false | | |
@ -2554,6 +2555,7 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
| `redirect_to_access_url` | boolean | false | | |
| `scim_api_key` | string | false | | |
| `secure_auth_cookie` | boolean | false | | |
| `session_lifetime` | [codersdk.SessionLifetime](#codersdksessionlifetime) | false | | |
| `ssh_keygen_algorithm` | string | false | | |
| `strict_transport_security` | integer | false | | |
| `strict_transport_security_options` | array of string | false | | |
@ -4294,6 +4296,24 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
| `ssh` | integer | false | | |
| `vscode` | integer | false | | |
## codersdk.SessionLifetime
```json
{
"default_duration": 0,
"disable_expiry_refresh": true,
"max_token_lifetime": 0
}
```
### Properties
| Name | Type | Required | Restrictions | Description |
| ------------------------ | ------- | -------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `default_duration` | integer | false | | Default duration is for api keys, not tokens. |
| `disable_expiry_refresh` | boolean | false | | Disable expiry refresh will disable automatically refreshing api keys when they are used from the api. This means the api key lifetime at creation is the lifetime of the api key. |
| `max_token_lifetime` | integer | false | | |
## codersdk.SupportConfig
```json

View File

@ -148,7 +148,7 @@ func New(ctx context.Context, options *Options) (_ *API, err error) {
DB: options.Database,
OAuth2Configs: oauthConfigs,
RedirectToLogin: false,
DisableSessionExpiryRefresh: options.DeploymentValues.DisableSessionExpiryRefresh.Value(),
DisableSessionExpiryRefresh: options.DeploymentValues.Sessions.DisableExpiryRefresh.Value(),
Optional: false,
SessionTokenFunc: nil, // Default behavior
PostAuthAdditionalHeadersFunc: options.PostAuthAdditionalHeadersFunc,
@ -157,7 +157,7 @@ func New(ctx context.Context, options *Options) (_ *API, err error) {
DB: options.Database,
OAuth2Configs: oauthConfigs,
RedirectToLogin: false,
DisableSessionExpiryRefresh: options.DeploymentValues.DisableSessionExpiryRefresh.Value(),
DisableSessionExpiryRefresh: options.DeploymentValues.Sessions.DisableExpiryRefresh.Value(),
Optional: true,
SessionTokenFunc: nil, // Default behavior
PostAuthAdditionalHeadersFunc: options.PostAuthAdditionalHeadersFunc,

View File

@ -427,13 +427,11 @@ export interface DeploymentValues {
readonly rate_limit?: RateLimitConfig;
readonly experiments?: string[];
readonly update_check?: boolean;
readonly max_token_lifetime?: number;
readonly swagger?: SwaggerConfig;
readonly logging?: LoggingConfig;
readonly dangerous?: DangerousConfig;
readonly disable_path_apps?: boolean;
readonly max_session_expiry?: number;
readonly disable_session_expiry_refresh?: boolean;
readonly session_lifetime?: SessionLifetime;
readonly disable_password_auth?: boolean;
readonly support?: SupportConfig;
readonly external_auth?: ExternalAuthConfig[];
@ -998,6 +996,13 @@ export interface SessionCountDeploymentStats {
readonly reconnecting_pty: number;
}
// From codersdk/deployment.go
export interface SessionLifetime {
readonly disable_expiry_refresh?: boolean;
readonly default_duration: number;
readonly max_token_lifetime?: number;
}
// From codersdk/deployment.go
export interface SupportConfig {
readonly links: LinkConfig[];