Skip to content

How access works

Every request to your app goes through the platform’s edge first. The edge signs the caller in, checks that the app is shared with them, and only then passes the request on, with a signed token that says who they are.

Your app has no other way in. A Worker has no route of its own on the internet, and a container has no public address.

Say Grace opens https://hello--acme.jiayang-apps.cloud/report for the first time.

  1. No session, so off to sign in. Grace’s browser has no session for this host yet. Because this is a page load, the edge redirects it to the dashboard at https://app.jiayang.cloud/sign-in. It also sets a short-lived cookie on the app’s host that remembers /report, for ten minutes.

    A request that isn’t a page load, such as a fetch from a script, gets 401 unauthorized instead of a redirect.

  2. Grace signs in to the dashboard. She types her email address and the six-digit code she gets by email. If her browser is already signed in to the dashboard, this step is skipped.

  3. The dashboard hands her back. It sends the browser to /.jiayang/session on the app’s host with a single-use code that works for 60 seconds. The edge checks that the code arrived in the same browser that left in step 1, trades it with the platform for a session on this one host, and sets it as a cookie. The browser goes on to /report.

  4. The edge checks the session. On this request and every one after it, the edge verifies the session cookie: its signature, who issued it, that it’s for this host and no other, and that it hasn’t expired.

  5. The edge checks the sharing. It asks the platform whether Grace may use this app, and with what role. If not, she gets 403 forbidden.

  6. The edge stamps the request. It removes every X-Jiayang-* header the browser sent. Then it signs a new identity token for Grace, valid for 60 seconds, and adds it as X-Jiayang-Identity, with her email in X-Jiayang-Email.

  7. The edge records it and passes it on. The request goes into the workspace’s audit log, then to your app. If the edge can’t write the log entry, the request doesn’t reach your app.

The edge keeps each app’s session in its own cookie, __Host-jiayang_session. The browser sends it only to that one host, over HTTPS, and page scripts can’t read it.

  • It lasts at most 12 hours, and never longer than the dashboard sign-in it came from.
  • Signing out of the dashboard ends every app session from that sign-in within 60 seconds.
  • Your app never sees the cookie. The edge removes it from each request before your app gets it, and drops any Set-Cookie from your app that uses the same name.

The edge lets a person in when one of these is true:

  • The app is shared with them, with any role.
  • The app’s visibility is workspace and they are a member of the workspace. They get the viewer role.

If the workspace limits its email domains, the person’s address has to be in one of them too, even when the app is shared with them.

Nobody else gets in, workspace owners and admins included: they manage every app, but they open a private one only after they share it with themselves. Workspaces and roles has the details.

Changes to sharing reach the edge within 60 seconds. That includes connections that are already open: the edge checks WebSockets, streams and long downloads again while they run, and closes them when access ends or the session expires.

If the edge can’t reach the platform to ask, it refuses the request with 503.

The one exception is a public path: a path you open to anyone in the dashboard, so a webhook sender can reach it at https://jiayang-apps.cloud/<workspace>/<app>/<path>. Requests there need no sign-in. Give the path a verifier and the platform checks each delivery’s signature first, and sends it on with a token of kind webhook; with none, requests arrive with no identity token. See Public paths and webhooks.

Situation Answer
A page load with no session A redirect to sign in
Any other request with no session 401 unauthorized
A session that has expired or been signed out The cookie is cleared. A page load goes to sign in again, anything else gets 401
Signed in and a member of the app’s workspace, but the app isn’t shared with you 403 forbidden. A page load gets a 403 page, You don’t have access to this app
Signed in, but the app isn’t shared with you and you aren’t in its workspace 404 not found. A page load gets a 404 page, Nothing to open here
Signed in, but there’s no app at this address, or nothing is deployed to it The same 404, and the same page
A POST or other write sent from another site’s page, another app included 403 forbidden
The edge can’t reach the platform 503 service unavailable
A Free workspace that has used what its plan includes this month, such as twice its monthly requests (200,000) A 402 page, Paused for the month
A container app in a workspace on the Free plan A 402 page, This app needs a paid plan
A suspended workspace A 403 page, App unavailable

Someone outside a workspace gets the same 404 for an app they can’t open as for one that isn’t there, so signing in doesn’t tell them which of the workspace’s apps exist.

Both pages say which address you’re signed in with. If the app was shared with another of your addresses, sign out in the dashboard and open the link again to sign in as that one.

X-Jiayang-Identity holds a JWT signed with RS256 by a key only the edge has. It lasts 60 seconds and is made out to one app. It says who is calling (a person’s email, or a bypass token’s id), their role on this app, and the workspace.

The public keys are at https://edge.jiayang.cloud/.well-known/jwks.json. The platform sets JIAYANG_APP_ID, JIAYANG_IDENTITY_ISSUER and JIAYANG_JWKS_URL in every app, so the SDKs need no configuration. Each SDK checks the signature, the issuer, that the audience is your app, and the expiry. A missing token, a bad one, or keys it can’t fetch all end in a refusal, never a pass.

The SDK overview shows the code for each language, every claim in the token, and each check.

On the platform, the edge removes any X-Jiayang-* header a client sends before it adds its own. So why verify the token rather than read X-Jiayang-Email?

  • Your code also runs where the edge isn’t in front of it: on your machine, in tests, behind whatever proxy you put in front of it next. There, a header says whatever the caller wrote.
  • The token is made out to your app and lasts 60 seconds. A token copied from a request to one app is refused by every other app, and after a minute it’s refused everywhere.
  • A request on a public path with no verifier reaches your app with no identity at all, and a verified webhook delivery carries a token of kind webhook, not a person’s. Code that verifies a person’s token refuses both by default.

Use X-Jiayang-Email to show a name. Verify X-Jiayang-Identity before you decide anything.

A script can’t sign in with a browser, so an app’s own address never lets one in. Machines call the app through the apps domain instead, with a bearer token:

Terminal window
curl -H "Authorization: Bearer $JIAYANG_TOKEN" https://jiayang-apps.cloud/acme/hello/report

The token is a bypass token made for that app, or your own CLI session, which is what jiayang curl uses. The request passes the same checks, and your app gets the same identity token, with kind set to service for a bypass token. See Tokens for scripts and machines.

  • It removes the Domain attribute from every cookie your app sets, so a cookie stays on your app’s host and can’t reach another app.
  • It drops any cookie named like the platform’s own.
  • It marks every response Cache-Control: private, so no shared cache keeps a page meant for one person. A max-age your app sends is kept, so the person’s own browser can still keep hashed files.

For more on how the platform keeps apps apart, see Security.