diff --git a/lib/mastodon/routes/oauth.js b/lib/mastodon/routes/oauth.js index 1d9a4ff..9bffd79 100644 --- a/lib/mastodon/routes/oauth.js +++ b/lib/mastodon/routes/oauth.js @@ -310,7 +310,7 @@ router.post("/oauth/authorize", async (req, res, next) => { "error_description", "The resource owner denied the request", ); - return res.redirect(url.toString()); + return redirectToUri(res, redirect_uri, url.toString()); } return res.status(403).json({ error: "access_denied", @@ -362,7 +362,7 @@ router.post("/oauth/authorize", async (req, res, next) => { // Redirect with code const url = new URL(redirect_uri); url.searchParams.set("code", code); - res.redirect(url.toString()); + redirectToUri(res, redirect_uri, url.toString()); } catch (error) { next(error); } @@ -600,4 +600,36 @@ function extractClientCredentials(req) { }; } +/** + * Redirect to a URI, handling custom schemes for native apps. + * + * HTTP(S) redirect URIs use a standard 302 redirect (web clients). + * Custom scheme URIs (fedilab://, moshidon-android-auth://) use an + * HTML page with JavaScript + meta refresh. Android Chrome Custom Tabs + * block 302 redirects to non-HTTP schemes but allow client-side navigation. + * + * @param {object} res - Express response + * @param {string} originalUri - The registered redirect_uri (to detect scheme) + * @param {string} fullUrl - The complete redirect URL with query params + */ +function redirectToUri(res, originalUri, fullUrl) { + if (originalUri.startsWith("http://") || originalUri.startsWith("https://")) { + return res.redirect(fullUrl); + } + + // Native app — HTML page with JS redirect + meta refresh fallback + res.type("html").send(` + +
+ + +Redirecting to application…
+ + +`); +} + export default router; diff --git a/package.json b/package.json index 1387b0d..a913e4e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rmdes/indiekit-endpoint-activitypub", - "version": "3.6.1", + "version": "3.6.2", "description": "ActivityPub federation endpoint for Indiekit via Fedify. Adds full fediverse support: actor, inbox, outbox, followers, following, syndication, and Mastodon migration.", "keywords": [ "indiekit",