Changeset 2d66d66 in Klonkt for src/routes


Ignore:
Timestamp:
07/19/2026 04:17:44 PM (7 weeks ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
33e1dbd
Parents:
4407c67
git-author:
Robin <roboburr@…> (07/19/2026 04:17:27 PM)
git-committer:
Robin <roboburr@…> (07/19/2026 04:17:44 PM)
Message:

Feature: revoke connected OAuth apps from the account page

You issue C2S bearer tokens (Shaer, etc.) but had no way to see or revoke them.
The account page now has a 'Connected apps' section listing every authorization
(app name via the client join, site, scope, last used) with a Revoke button.
Already-issued tokens appear because they were always stored (hashed) with the
user/client/site; the bearer is never kept, so revocation is keyed on the safe
token_hash and scoped to the owner (you cannot revoke someone else's).

  • OAuthService.listAuthorizations(userId) / revokeAuthorization(userId, hash).
  • account.js: authorizations passed to the page; POST /account/oauth/revoke.
  • account.ejs: the section + styles; i18n NL/EN/DE. Visible to viewers too (revoking your own app access is a safety action).

83 tests green. Live-verified: two apps listed on /account, revoke one -> it is
gone and the other stays, token count drops in the DB.

Co-Authored-By: Claude Opus 4.8 <noreply@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/routes/account.js

    r4407c67 r2d66d66  
    2323import { getPrimarySite } from '../middleware/site.js';
    2424import { renderPage } from '../middleware/render.js';
     25import OAuth from '../services/OAuthService.js';
     26import { t } from '../services/i18n.js';
    2527import { requireAuth } from '../middleware/auth.js';
    2628import { toWebp } from '../services/ImageWebpService.js';
     
    7577    // Display fallback: when you have no own account avatar, show your site's photo.
    7678    siteAvatar: editableSite ? editableSite.profile_photo : null,
     79    // OAuth apps (C2S) this user has authorized, so they can revoke them here.
     80    authorizations: OAuth.listAuthorizations(req.session.user.id),
    7781    success: req.query.success || null,
    7882    error: req.query.error || null,
    7983  });
     84});
     85
     86// ==================== REVOKE AN OAUTH APP AUTHORIZATION ====================
     87router.post('/oauth/revoke', requireAuth, (req, res) => {
     88  const lang = req.session.lang || (req.session.user && req.session.user.lang) || 'nl';
     89  const ok = OAuth.revokeAuthorization(req.session.user.id, req.body.token_hash);
     90  const msg = ok ? t(lang, 'acct.oauth_revoked') : t(lang, 'acct.oauth_revoke_none');
     91  res.redirect('/account?' + (ok ? 'success' : 'error') + '=' + encodeURIComponent(msg));
    8092});
    8193
Note: See TracChangeset for help on using the changeset viewer.