TestOAuth2RefreshExpiryOutlivesAccess verifies that refresh token expiry is greater than the provisioned access token (API key) expiry per configuration.
(t *testing.T)
| 1229 | // TestOAuth2RefreshExpiryOutlivesAccess verifies that refresh token expiry is |
| 1230 | // greater than the provisioned access token (API key) expiry per configuration. |
| 1231 | func TestOAuth2RefreshExpiryOutlivesAccess(t *testing.T) { |
| 1232 | t.Parallel() |
| 1233 | |
| 1234 | // Set explicit lifetimes to make comparison deterministic. |
| 1235 | db, pubsub := dbtestutil.NewDB(t) |
| 1236 | dv := coderdtest.DeploymentValues(t, func(d *codersdk.DeploymentValues) { |
| 1237 | d.Sessions.DefaultDuration = serpent.Duration(1 * time.Hour) |
| 1238 | d.Sessions.RefreshDefaultDuration = serpent.Duration(48 * time.Hour) |
| 1239 | }) |
| 1240 | ownerClient := coderdtest.New(t, &coderdtest.Options{ |
| 1241 | Database: db, |
| 1242 | Pubsub: pubsub, |
| 1243 | DeploymentValues: dv, |
| 1244 | }) |
| 1245 | _ = coderdtest.CreateFirstUser(t, ownerClient) |
| 1246 | ctx := testutil.Context(t, testutil.WaitLong) |
| 1247 | |
| 1248 | // Create app and secret |
| 1249 | // Keep suffix short to satisfy name validation (<=32 chars, alnum + hyphens). |
| 1250 | apps := generateApps(ctx, t, ownerClient, "ref-exp") |
| 1251 | //nolint:gocritic // Owner permission required for app secret creation |
| 1252 | secret, err := ownerClient.PostOAuth2ProviderAppSecret(ctx, apps.Default.ID) |
| 1253 | require.NoError(t, err) |
| 1254 | |
| 1255 | cfg := &oauth2.Config{ |
| 1256 | ClientID: apps.Default.ID.String(), |
| 1257 | ClientSecret: secret.ClientSecretFull, |
| 1258 | Endpoint: oauth2.Endpoint{ |
| 1259 | AuthURL: apps.Default.Endpoints.Authorization, |
| 1260 | DeviceAuthURL: apps.Default.Endpoints.DeviceAuth, |
| 1261 | TokenURL: apps.Default.Endpoints.Token, |
| 1262 | AuthStyle: oauth2.AuthStyleInParams, |
| 1263 | }, |
| 1264 | RedirectURL: apps.Default.CallbackURL, |
| 1265 | Scopes: []string{}, |
| 1266 | } |
| 1267 | |
| 1268 | // Authorization and token exchange |
| 1269 | code, verifier, err := authorizationFlow(ctx, ownerClient, cfg) |
| 1270 | require.NoError(t, err) |
| 1271 | tok, err := cfg.Exchange(ctx, code, |
| 1272 | oauth2.SetAuthURLParam("code_verifier", verifier), |
| 1273 | ) |
| 1274 | require.NoError(t, err) |
| 1275 | require.NotEmpty(t, tok.AccessToken) |
| 1276 | require.NotEmpty(t, tok.RefreshToken) |
| 1277 | |
| 1278 | // Parse refresh token prefix (coder_<prefix>_<secret>) |
| 1279 | parts := strings.Split(tok.RefreshToken, "_") |
| 1280 | require.Len(t, parts, 3) |
| 1281 | prefix := parts[1] |
| 1282 | |
| 1283 | // Look up refresh token row and associated API key |
| 1284 | dbToken, err := db.GetOAuth2ProviderAppTokenByPrefix(dbauthz.AsSystemRestricted(ctx), []byte(prefix)) |
| 1285 | require.NoError(t, err) |
| 1286 | apiKey, err := db.GetAPIKeyByID(dbauthz.AsSystemRestricted(ctx), dbToken.APIKeyID) |
| 1287 | require.NoError(t, err) |
| 1288 |
nothing calls this directly
no test coverage detected