VibeHost
Guides

Share links

Cookie-issuing URLs that grant temporary access to private or password-gated apps.

A share link is a URL that, when visited, sets a cookie in the visitor's browser. The cookie satisfies the share-link gate (see Grants and visibility) for that browser, for as long as the share link is active.

Use share links when you want to give someone access without making them sign up — clients reviewing previews, designers sanity-checking mockups, journalists embargo-previewing a launch.

Create

vibehost app share-link create --app my-site

Output:

{
  "ok": true,
  "data": {
    "id": "shr_abc123",
    "url": "https://my-site.vibehost.space/_share/vhs_abc123def",
    "label": null,
    "createdAt": "2026-05-23T08:00:00Z",
    "expiresAt": null,
    "revokedAt": null
  }
}

Send data.url to the recipient. The first time they open it, their browser gets a signed 24-hour cookie (vh_app_share_<appId>) that satisfies the share-link gate (visibility/grant) on subsequent requests. If the app has a password set, the visitor will still be prompted for it — the password gate is separate and always applies.

Options:

vibehost app share-link create --app my-site \
  --label "Acme review — Q2 pitch" \
  --expires 14d
  • --label — searchable note. Shows up in share-link ls and in the dashboard. Pick something you'll recognize in 6 months.
  • --expires — duration (24h, 7d, 14d, 30d) OR ISO timestamp. After expiry the link returns 410.

List + revoke

Plain ls shows the active links; --include-revoked adds revoked + expired ones; --json is for filtering with jq.

vibehost app share-link ls --app my-site
vibehost app share-link ls --app my-site --include-revoked
vibehost app share-link ls --app my-site --json

Revoke by full ID or unique prefix (the second form below is a prefix match):

vibehost app share-link revoke shr_abc123def --app my-site
vibehost app share-link revoke vhs_abc --app my-site

Revocation is immediate — the cookie persists in the visitor's browser but the dispatcher rejects it on next request.

Three scenarios

You're delivering a landing page; the client should see it for 2 weeks, after that the link auto-expires. Setting the app private means only grantees plus the share-link can reach it.

vibehost app visibility client-pitch private
vibehost app share-link create --app client-pitch \
  --label "Acme Q2 review" \
  --expires 14d

Email the URL to the client. They click; they're in; no sign-up.

After 14 days the link returns 410 Gone. To extend:

vibehost app share-link create --app client-pitch \
  --label "Acme Q2 review — extension" \
  --expires 14d

Revoke the old one (share-link revoke <id>) once the new one is sent.

Internal reviewer who isn't in your VibeHost workspace, but you don't want to add them as a workspace member.

Option A — keep the app workspace-scoped, add the reviewer by email:

vibehost app grants add-email reviewer@partner.com viewer --app new-feature

Option B — share link, no sign-up needed:

vibehost app visibility new-feature private
vibehost app share-link create --app new-feature \
  --label "Internal review – security team" \
  --expires 7d

Option A is preferred for repeat reviewers (audit trail by user). Option B for one-off "open this once and look at it".

You're launching with a press embargo. Reporters get the URL 48h before public launch; after launch the link auto-revokes (and the app goes public).

vibehost app visibility upcoming-launch private
vibehost app share-link create --app upcoming-launch \
  --label "NYT embargo" \
  --expires 48h
vibehost app share-link create --app upcoming-launch \
  --label "TechCrunch embargo" \
  --expires 48h

Two separate links — separately revocable, separately tracked in audit. At launch, flip the app public. Optionally, revoke the embargo links too so press can't keep linking the share URL:

vibehost app visibility upcoming-launch public
vibehost app share-link ls --app upcoming-launch --json | \
  jq -r '.data[] | .id' | \
  xargs -I{} vibehost app share-link revoke {} --app upcoming-launch

How it works on the wire

  1. Visitor clicks https://my-site.vibehost.space/_share/vhs_abc123def.
  2. Dispatcher validates the token (shr_abc123 → not revoked, not expired), sets a signed 24-hour cookie:
    Set-Cookie: vh_app_share_<appId>=<HMAC-signed-payload>;
                Path=/; Max-Age=86400; Secure; HttpOnly; SameSite=Lax
  3. Dispatcher 302-redirects to the actual URL.
  4. The follow-up request carries the share cookie. The share-link gate sees it and satisfies visibility/grant for this browser — those checks are skipped on every subsequent request as long as the cookie is valid and the share row is still active. The server then runs the password gate: if the app has a password set and there's no valid password cookie, the visitor gets a 401 password prompt. After they enter the password, the server sets a second cookie (vh_app_pw_<appId>, 7-day TTL).
  5. With both cookies in place, all subsequent requests in this browser pass: share cookie covers visibility/grant (24 hours); password cookie covers the password gate (7 days). The asymmetric TTLs are deliberate — share cookies belong to outside parties and stay narrow; password cookies belong to viewers re-entering an app they're actively using. Either expiring first just re-prompts that one factor.

The cookie is bound to one app (different apps issue different cookies). One share link can't unlock other apps in the same workspace.

Best practices

One link per recipient

Easier to revoke individual access without locking everyone else out.

Always set --expires

Forever-links accumulate. 7–30 days is a reasonable default.

Combine with private visibility

Set the app private + create share links. The app is invisible to anyone without a link or a grant.

Audit quarterly

share-link ls --include-revoked --json and verify nothing long-lived is left over from old projects.

  • They don't authenticate the visitor. The cookie is bound to the share link, not the person. Anyone with the URL can satisfy the gate.
  • They don't bypass the password gate. A valid share-link cookie satisfies the share-link gate (visibility/grant are skipped) for the app it was minted on — including visibility: private apps with no grants. But if the app has a password set, the visitor still has to enter it; the password cookie is separate and always required. This is by design: minting a share link IS the operator's explicit consent for "anyone with this URL can view (no sign-in required)", but it doesn't override an explicitly set password. If "anyone with this URL, no further friction" is what you want, don't set a password. If "anyone with this URL and this password" is what you want, set both.
  • They don't expire by default. Set --expires or revoke manually.
  • They don't carry an audit trail of the recipient. If you need "person X opened this on date Y", invite them with a grant instead.

Common errors

CodeStatusMeaning
NOT_FOUND404Share link ID doesn't exist or was revoked + you used a prefix shorter than the unique prefix
RELEASE_GONE410Share link expired (expiresAt in the past). Create a new one.
UNAUTHENTICATED401Token in URL was invalid / expired AND no other gate (session, grant) lets the viewer in. The dispatcher falls back to the standard login prompt.

On this page