Setting the redirect URL

OAuth Redirect URI App registration Security
Who this article is for
For developers registering an app in the ReceiptRoller developer portal. It explains how to set the redirect URI (callback URL) used in the OAuth 2.0 authorization code flow, and the cautions involved.

The redirect URI is the URL that receives the authorization code after the user presses "Allow" on the authorization screen in the OAuth flow. The URI you register at app registration and the redirect_uri you specify when actually sending a request to /oauth/authorize must match exactly.

The role of the redirect URI

In the OAuth authorization code flow, the values are passed in the following order.

  1. The app sends the user to ReceiptRoller's authorization screen (including redirect_uri)
  2. The user presses "Allow"
  3. ReceiptRoller redirects to the registered redirect URI with a code parameter
  4. The app obtains an access token using the code

If you specify a redirect URI that is not registered, or one that differs by even a single character from the registered value, ReceiptRoller does not return an authorization code and instead returns an invalid_redirect_uri error. This is a mechanism to prevent an attacker from stealing the code.

Registration rules

Item Rule
Scheme https:// required (production)
http://localhost and http://127.0.0.1 allowed only in development
Host A fully qualified domain name. Wildcards (*.example.com) not allowed
Path Arbitrary. A conventional path such as /oauth/callback or /auth/rr/callback is recommended
Query / fragment Do not include them in the registered URI. Pass dynamic parameters via state
Number registrable Up to 10 per app
Case sensitivity Distinguished. /Callback and /callback are different
Trailing slash Distinguished. /callback and /callback/ are different

Using development vs. production environments

Many apps have multiple environments: "development", "staging", "production". On ReceiptRoller you can register multiple redirect URIs per app, so adding a URI per environment is the basic approach.

Recommended pattern

https://app.example.com/oauth/callback           ← production
https://staging.example.com/oauth/callback       ← staging
http://localhost:3000/oauth/callback             ← development (local)

You can also separate apps by environment, but we strongly recommend always separating the production app from the development app. The reasons are as follows.

  • You no longer need to distribute the production client secret to every developer
  • You prevent accidents where a development-time glitch mistakenly invalidates production users' tokens
  • User-scope review completes for the production app alone
Note: do not register http://localhost for a production app. If a secret leaks, an attacker could lure authorization codes to a fake local site.

Registration procedure

  1. Developer portal → app list → open the target app
  2. Click the "+ Add" button in the "Redirect URI" section
  3. Enter the URI and "Save"
  4. Repeat for as many environments as needed

Registered URIs take effect immediately. No rebuild or redeploy of the app is needed.

Leveraging the state parameter

Pass dynamic information (the URL of the page you came from, the user ID, a CSRF token, etc.) via the state parameter rather than embedding it directly in the redirect URI. ReceiptRoller returns state as-is after authorization, so you can restore it on the callback side.

// Authorization request
https://receiptroller.io/oauth/authorize
  ?client_id=xxx
  &redirect_uri=https://app.example.com/oauth/callback
  &state=eyJjc3JmIjoiYWJjMTIzIiwicmV0dXJuIjoiL2Rhc2hib2FyZCJ9
  &scope=store.read
  &response_type=code

// Callback
https://app.example.com/oauth/callback
  ?code=...
  &state=eyJjc3JmIjoiYWJjMTIzIiwicmV0dXJuIjoiL2Rhc2hib2FyZCJ9

state is also required as a CSRF countermeasure. Save a random value generated at request time in the session, and verify it matches on callback.

Common errors

Error Cause What to do
invalid_redirect_uri Does not match the registered URI Check that it matches exactly, including case, trailing slash, and port
redirect_uri_required The authorization request does not include redirect_uri Always add it to the query parameters
insecure_redirect_uri Tried to register http:// (other than localhost) on a production app Change it to https://
No callback after authorization DNS/certificate error on the registered URI's host Open that URI directly in a browser to confirm reachability

Cautions when changing it

When changing the redirect URI of a live app, follow this order.

  1. Add the new URI (keep the old URI)
  2. Switch the app's code / environment variables to the new URI and deploy
  3. Verify behavior with the new URI
  4. Delete the old URI

If you delete the old URI abruptly, all authorization requests that occur before the deploy completes will fail.

Related guides

Published: 2026-04-27 Updated: 2026-07-05
Tags
API (22) OAuth (15) Android (10) iOS (9) Webhook (6) Troubleshooting (5) api (5) App registration (4) POS Integration (4) Reference (4)
Related articles