mirror of
https://github.com/svemagie/indiekit-endpoint-activitypub.git
synced 2026-04-02 15:44:58 +02:00
fix: use HTML+JS redirect for native app OAuth callbacks
Android Chrome Custom Tabs block 302 redirects to custom URI schemes (fedilab://, moshidon-android-auth://) for security. The server sends the redirect correctly but the WebView silently ignores it — "nothing happens" when the user taps Authorize. Fix: detect non-HTTP redirect URIs and render an HTML page with both a JavaScript window.location redirect and a meta refresh fallback. Client-side navigation to custom schemes is allowed by WebViews. HTTP(S) redirect URIs (Phanpy, Elk) still use standard 302.
This commit is contained in:
@@ -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(`<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0;url=${fullUrl}">
|
||||
<title>Redirecting…</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Redirecting to application…</p>
|
||||
<script>window.location.href = ${JSON.stringify(fullUrl)};</script>
|
||||
</body>
|
||||
</html>`);
|
||||
}
|
||||
|
||||
export default router;
|
||||
|
||||
Reference in New Issue
Block a user