Going live on a public URL
Your app must be reachable on the public internet, over HTTPS, at the address you registered. This page is what to prepare, and the checklist the SuperPreneur team goes through before setting your app to Active.
Environments
| Environment |
Identity provider address |
Client id and secret |
Use |
| Sandbox |
https://superapp.ideapreneurnepal.com/sandbox |
sandbox_app and sandbox_secret, the same for everyone |
Testing with fake users, with no registration. See The sandbox |
| Hosted |
https://superapp.ideapreneurnepal.com |
Issued after review |
Real users |
Each environment has its own credentials, and a sandbox token is useless on the hosted service and the other way round, so testing can never touch real users. Switching from one to the other is changing three environment variables:
| Variable |
Value |
IDP_URL |
The identity provider address for this environment |
CLIENT_ID, CLIENT_SECRET |
Your credentials for this environment |
SHELL_ORIGIN |
The web shell's origin, used in frame-ancestors and for the browser handshake |
PORT |
The port your server listens on behind your reverse proxy |
Your public address
| Requirement |
Detail |
| HTTPS |
A valid certificate from a public authority (not self-signed), TLS 1.2 or newer. Plain http is allowed only for localhost while developing |
| One stable origin |
The launch URL you register fixes your origin (scheme, host and port). Keep every page on it, and do not later redirect to another host such as www. Messages from any other origin are ignored and the container refuses to navigate away |
| API on the same origin |
The example page calls /api/... relative to itself. If your API lives on another host, allow cross-origin requests from your page's origin only, and change the calls |
| Mobile first |
The app opens full screen in a phone webview. Set the viewport meta tag, keep text at 16 px or more, make touch targets 44 px or larger, and test at 360 px width |
| Fast on mobile data |
Compress responses and keep the first screen light |
| No outside links |
Navigating to another site inside the container is blocked. Do not depend on opening other sites, and do not open new windows |
| Header |
Where |
Why |
Content-Security-Policy: frame-ancestors 'self' <shell origin> |
Every page |
Only the SuperPreneur web shell may frame you. The phone app does not frame you, so this costs nothing there |
No X-Frame-Options: DENY or SAMEORIGIN |
Every page |
Either would stop the web shell from showing your app |
Cache-Control: no-store |
Every /api/* response |
Nonces, sessions and personal data must not be cached |
Strict-Transport-Security: max-age=31536000 |
Every response |
Keeps browsers on HTTPS (recommended) |
X-Content-Type-Options: nosniff |
Every response |
Stops browsers guessing file types (recommended) |
Running more than one server
The examples keep nonces and sessions in memory. One instance is fine, and a restart is harmless because the page signs in again silently. Behind a load balancer with several instances, store nonces and sessions in something shared such as Redis (see Generating the nonce), or a request will reach an instance that has never seen them.
Talking to the identity provider
| Topic |
Guidance |
| Network |
Your server needs outbound HTTPS to the identity provider's address |
| User-Agent |
Send your own User-Agent header (for example my-app/1.0) on the verify call. The hosted service sits behind a firewall that answers 403 to the default agent of some HTTP libraries, Python's urllib included. The Python example sets one |
| Timeout |
5 seconds, as the examples do |
| Retries |
A 400 or 401 from verify is final: do not retry. A timeout or 5xx may be retried once, or shown to the user as "Try again" |
| Unreachable |
The examples answer 401 with idp_unreachable; treat it as temporary |
| Secrets |
Keep the secret in an environment variable or a secret manager, never in code or git. If it leaks, tell us and we issue a new one, and the old one stops working immediately |
| Clock |
The identity provider checks token expiry, so your clock does not matter for verify. If you also check signatures yourself (see Request and response examples), allow 5 seconds of difference |
Privacy and data
- Store only what your app needs, and key it by
sub.
- Have a privacy policy page and a support contact ready; the listing review asks for both.
- Be ready to delete a user's data when they ask. A disconnect webhook that tells you when someone revokes access is planned.
- Which Nepali data-protection rules apply to you is a question for your own legal adviser; this guide does not cover it.
Go-live checklist
| # |
Check |
Done when |
| 1 |
Public HTTPS |
Your launch URL opens in a browser with a valid certificate, with no redirect to another host |
| 2 |
Configuration |
Credentials come from environment variables and are not in code or git |
| 3 |
Test routes off |
DEV_TOOLS and similar are unset; the test routes return 404 |
| 4 |
Outside SuperPreneur |
Opening your address directly shows an "open from SuperPreneur" message, and every data route answers 401 |
| 5 |
Handshake |
Signing in works, and still works silently after your server restarts |
| 6 |
Headers |
The frame-ancestors header is present and X-Frame-Options is not |
| 7 |
Real devices |
Works inside the phone app on one iPhone and one Android phone, on mobile data |
| 8 |
Your user flows |
Every flow of your app has been walked through (Testing your app lists them) |
| 9 |
Errors |
Failures show a plain sentence and a way forward, never a raw code or a blank screen |
| 10 |
Logs |
No tokens, secrets or sessions appear in them |
| 11 |
Monitoring |
A health route (for example GET /healthz returning 200) and an alert if it stops answering |
| 12 |
Listing details |
Name, description, category, keywords, icon, privacy policy and support contact are agreed |
When these pass, the SuperPreneur team sets your app to Active. If anything goes wrong later we can set it to Suspended at once, which removes it from search and stops new launches.