@rmdes/indiekit-endpoint-activitypub 3.5.3 → 3.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -158,7 +158,7 @@ router.get("/.well-known/oauth-authorization-server", (req, res) => {
158
158
  "write:statuses",
159
159
  ],
160
160
  response_types_supported: ["code"],
161
- grant_types_supported: ["authorization_code", "client_credentials"],
161
+ grant_types_supported: ["authorization_code", "client_credentials", "refresh_token"],
162
162
  token_endpoint_auth_methods_supported: [
163
163
  "client_secret_basic",
164
164
  "client_secret_post",
@@ -423,10 +423,49 @@ router.post("/oauth/token", async (req, res, next) => {
423
423
  });
424
424
  }
425
425
 
426
+ // ─── Refresh token grant ──────────────────────────────────────────
427
+ if (grant_type === "refresh_token") {
428
+ const { refresh_token } = req.body;
429
+ if (!refresh_token) {
430
+ return res.status(400).json({
431
+ error: "invalid_request",
432
+ error_description: "Missing refresh_token",
433
+ });
434
+ }
435
+
436
+ const existing = await collections.ap_oauth_tokens.findOne({
437
+ refreshToken: refresh_token,
438
+ revokedAt: null,
439
+ });
440
+
441
+ if (!existing) {
442
+ return res.status(400).json({
443
+ error: "invalid_grant",
444
+ error_description: "Refresh token is invalid or revoked",
445
+ });
446
+ }
447
+
448
+ // Rotate: new access token + new refresh token
449
+ const newAccessToken = randomHex(64);
450
+ const newRefreshToken = randomHex(64);
451
+ await collections.ap_oauth_tokens.updateOne(
452
+ { _id: existing._id },
453
+ { $set: { accessToken: newAccessToken, refreshToken: newRefreshToken } },
454
+ );
455
+
456
+ return res.json({
457
+ access_token: newAccessToken,
458
+ token_type: "Bearer",
459
+ scope: existing.scopes.join(" "),
460
+ created_at: Math.floor(existing.createdAt.getTime() / 1000),
461
+ refresh_token: newRefreshToken,
462
+ });
463
+ }
464
+
426
465
  if (grant_type !== "authorization_code") {
427
466
  return res.status(400).json({
428
467
  error: "unsupported_grant_type",
429
- error_description: "Only authorization_code and client_credentials are supported",
468
+ error_description: "Only authorization_code, client_credentials, and refresh_token are supported",
430
469
  });
431
470
  }
432
471
 
@@ -487,11 +526,13 @@ router.post("/oauth/token", async (req, res, next) => {
487
526
  }
488
527
  }
489
528
 
490
- // Generate access token
529
+ // Generate access token and refresh token.
530
+ // Clear expiresAt — it was set for the auth code, not the access token.
491
531
  const accessToken = randomHex(64);
532
+ const refreshToken = randomHex(64);
492
533
  await collections.ap_oauth_tokens.updateOne(
493
534
  { _id: grant._id },
494
- { $set: { accessToken } },
535
+ { $set: { accessToken, refreshToken, expiresAt: null } },
495
536
  );
496
537
 
497
538
  res.json({
@@ -499,6 +540,7 @@ router.post("/oauth/token", async (req, res, next) => {
499
540
  token_type: "Bearer",
500
541
  scope: grant.scopes.join(" "),
501
542
  created_at: Math.floor(grant.createdAt.getTime() / 1000),
543
+ refresh_token: refreshToken,
502
544
  });
503
545
  } catch (error) {
504
546
  next(error);
@@ -519,8 +561,9 @@ router.post("/oauth/revoke", async (req, res, next) => {
519
561
  }
520
562
 
521
563
  const collections = req.app.locals.mastodonCollections;
564
+ // Match by access token or refresh token
522
565
  await collections.ap_oauth_tokens.updateOne(
523
- { accessToken: token },
566
+ { $or: [{ accessToken: token }, { refreshToken: token }] },
524
567
  { $set: { revokedAt: new Date() } },
525
568
  );
526
569
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rmdes/indiekit-endpoint-activitypub",
3
- "version": "3.5.3",
3
+ "version": "3.5.4",
4
4
  "description": "ActivityPub federation endpoint for Indiekit via Fedify. Adds full fediverse support: actor, inbox, outbox, followers, following, syndication, and Mastodon migration.",
5
5
  "keywords": [
6
6
  "indiekit",