Redirect URIs Are OAuth Trust Boundaries
Community apps for Slack, Discord, GitHub, and identity providers often fail at the callback layer. Exact redirect matching, state, PKCE, and callback ownership decide where tokens land.
OAuth risk in community apps is often discussed as a scope problem: which permissions did the user grant, and what can the app do afterward? That is necessary, but it misses an earlier boundary. Before an app receives a token, the authorization server has to decide where to send the authorization response. If the redirect URI, callback route, state value, or PKCE verifier is weak, the token flow can be steered away from the app owner or bound to the wrong session.
For Discord bots, Slack apps, GitHub OAuth apps, marketplace integrations, and private community tools, the redirect layer deserves the same review as scopes and token storage. Exact redirect matching, callback ownership, open-redirect testing, state validation, PKCE, and separate development callbacks are not paperwork. They decide whether an authorization grant returns to the intended application.
Key Takeaways
- check_circle The redirect URI is a security boundary because authorization codes, state values, and sometimes tokens return through that URL.
- check_circle Pattern matching is fragile. RFC 9700 recommends exact redirect URI matching except for the native-app localhost port case.
- check_circle The state parameter and PKCE solve different problems. State binds the response to the user's session, while PKCE helps protect the authorization code from interception or injection.
- check_circle A callback endpoint must not be an open redirector, proxy arbitrary destinations, or share a broad route with unrelated marketing and documentation paths.
- check_circle Development, staging, preview, and localhost callbacks should be separate from production apps and removed when they are no longer used.
- check_circle Community operators should inventory OAuth apps by callback URL, not only by scopes, because a stale callback can outlive the team that created it.
Why The Callback Matters
OAuth lets a user approve access at an authorization server and return to an application with an authorization code or token response. That return path is the redirect URI. In a clean authorization-code flow, the app receives a short-lived code at its callback endpoint, validates state, then exchanges the code at the token endpoint using the expected client credentials and PKCE material where applicable.
If the callback is wrong, the rest of the flow starts from a bad premise. A malicious or stale redirect URL can receive a code. An open redirect can forward a response to another site. A missing state check can bind an attacker-initiated authorization to a victim's session. A missing PKCE verifier can make code interception more useful. These are not theoretical details for large identity teams only. Small community apps often copy OAuth samples, add multiple callback URLs during setup, and then forget which ones remain active.
Exact Matching Beats Pattern Matching
RFC 9700, the OAuth 2.0 Security Best Current Practice, is blunt about redirect validation. It says the complexity of pattern matching creates security issues and advises exact redirection URI matching. The authorization server should ensure the two URIs are equal, with the specific native-app exception for localhost variable ports described in RFC 8252.
That guidance is useful because callback URLs are easy to over-broaden. A team may allow an entire domain, a wildcard subdomain, every path under a product site, or any URL that starts with a shared prefix. Each shortcut creates room for route confusion. If a documentation path, marketing redirect, file preview, or legacy route can redirect again, the OAuth response can move from an intended callback to an attacker-controlled destination.
State And PKCE Are Not Substitutes
The state parameter is a session binding tool. Discord's OAuth documentation recommends generating a unique value for a user's request, storing it somewhere protected by the client and user, and validating that the returned value matches before accepting the authorization response. Slack similarly tells developers to check the state parameter and treat a mismatch as a forgery. State helps answer: is this response tied to the authorization request this user actually started?
PKCE answers a different question. RFC 7636 was designed because public clients can be exposed to authorization code interception attacks. The client creates a verifier, sends a derived challenge in the authorization request, and later proves possession of the verifier during token exchange. A stolen code without the verifier should not be enough. Modern web and native apps should use PKCE even when a provider still treats it as optional, because copied sample code and mixed deployment models often blur the line between confidential and public clients.
Native And Desktop Apps Need Separate Rules
Native apps cannot protect a traditional client secret the way a server can. RFC 8252 therefore gives native apps specific redirect patterns, including private-use URI schemes, claimed HTTPS redirects, and loopback interface redirects. It also warns against embedded user agents because the hosting app can observe credentials, copy session cookies, and train users to sign in without normal browser protections.
For community tools, this matters when a desktop moderation utility, CLI, game launcher, or local admin panel adds OAuth login. Localhost callbacks should use loopback literals where supported, accept only the expected path, and rely on PKCE. They should not share the same OAuth application as the production web app unless the provider and threat model support that safely. A leaked desktop callback or old localhost configuration should not be able to receive production community grants indefinitely.
Platform Details Matter
Providers implement the redirect boundary differently. Slack requires HTTPS redirect URLs for app installs and says that when multiple redirect URLs are configured, the same redirect_uri must be sent in the authorize and access steps. It also allows a redirect_uri to match or be a subdirectory of a configured redirect URL. GitHub says an optional redirect_uri must have a host and port that match the configured callback URL, with the path referencing a subdirectory; it also documents a loopback exception for native applications. Discord requires a registered redirect URI in the authorization URL and returns state when it was supplied.
Those differences are not excuses for loose review. They are reasons to keep per-provider notes in the app inventory. An app that is safe under one provider's exact matching behavior may be unsafe when copied to another provider that allows subdirectories or subdomains. A callback route that is harmless for sign-in may be risky for a bot install flow that adds server permissions or returns webhook access.
Callback Ownership Is Operations Work
A callback URL belongs in the same asset inventory as a token store. Who owns the domain? Which team owns the route? Is the TLS certificate monitored? Does the route still exist after a frontend migration? Can a preview deployment, abandoned subdomain, or deleted serverless function claim the path? Does the endpoint log authorization codes or state values? Does it accept GET and POST bodies in a way that can leak credentials to analytics or error pages?
Community operators often focus on removing unused bots while stale OAuth applications remain alive in developer portals. That is backwards. A stale app with a live callback can still be authorized by a user if the client remains available. If the callback domain changes ownership, the risk can become worse than a forgotten token because new grants can be created. Review callback URLs during offboarding, domain migrations, provider changes, and incident response.
What To Test Before Approval
Before a community app is approved for Slack, Discord, GitHub, Google, or an identity provider, test the redirect boundary directly. Attempt to authorize with an unregistered redirect URI. Attempt a close variant: http instead of https, a changed port, a different subdomain, a sibling path, a trailing slash change, an encoded open-redirect parameter, and a fragment. The expected result should be denial unless the provider's documented rules explicitly allow it and the app owner accepts that risk.
Then test the application callback. Confirm it rejects missing or mismatched state, requires the expected PKCE verifier where supported, does not forward codes to arbitrary destinations, does not write codes or tokens into logs, and displays a safe completion page that does not load third-party scripts with secrets in the URL. Finally, remove every callback created for experiments, demos, old staging sites, and personal developer machines.
Checklist
- List every OAuth app, provider, redirect URI, callback owner, environment, and last-used date.
- Prefer exact redirect URI matching and avoid wildcard domains, broad prefixes, and shared catch-all routes.
- Validate state on every authorization response and fail closed on missing, repeated, expired, or mismatched values.
- Use PKCE for public clients, native apps, desktop tools, and web apps where the provider supports it.
- Test callback routes for open redirect behavior, token logging, analytics leakage, and unsafe third-party scripts.
- Remove stale development, staging, preview, localhost, and abandoned-domain callbacks before they become forgotten trust paths.
Sources
- RFC 9700: Best Current Practice for OAuth 2.0 Security open_in_new
- RFC 7636: Proof Key for Code Exchange by OAuth Public Clients open_in_new
- RFC 8252: OAuth 2.0 for Native Apps open_in_new
- Slack Developer Docs: Installing with OAuth open_in_new
- Discord Developer Docs: OAuth2 open_in_new
- GitHub Docs: Authorizing OAuth apps open_in_new
- Google Identity: Using OAuth 2.0 for Web Server Applications open_in_new
Continue Reading
Mobile App Logs Can Become Private Chat Data
Debug logs, crash reports, and support bundles can capture identifiers, tokens, message snippets, and device context. Chat apps need logging policy before troubleshooting becomes data exposure.
Russian Messaging Phishing Turns Backup Keys Into Account Access
FBI, CISA, and State Department updates on UNC5792 and UNC4221 show how Signal and WhatsApp account phishing is moving from linked devices to backup recovery keys.
Bot Tokens Need Rotation Before The Leak
Discord, Slack, Telegram, and GitHub automation tokens are production credentials. Communities need ownership, storage, rotation, revocation, and leak-response policy before a bot becomes the breach path.