# Chrome extension

The Hephaestus Chrome extension shows a practice review after the description of the pull request, merge request, or issue open in a person's tab. It shows links to comments Hephaestus posted there for them, the review time, and the conclusions about their own work. Each reader sees only their own records. A workspace admin gets a **Review details** link to the web app for every developer's observations, feedback delivery, and reviews. On a repository's list, a person can preview one row's work as one line inside the row. [The user guide](/user/browser-extension.md) describes what they see.

The extension runs on desktop Chrome only. It is not yet in the Chrome Web Store. Until publication, you distribute a build yourself (see [Deploy it to your users](#deploy-it-to-your-users)). An unpacked build without a manifest public key has an installation-dependent id. Read the actual id from Chrome. Keep its installation directory stable.

A store draft supplies a stable id before publication. The [contributor release guide](/contributor/browser-extension.md#releasing-to-the-chrome-web-store) explains how to test a build with that id.

## Allow the extension to sign in

An instance accepts sign-ins only from extensions in its list. The list is empty by default. Nothing changes until you set it:

```
# Comma-separated exact Chrome extension ids

HEPHAESTUS_AUTH_BROWSER_EXTENSION_IDS=abcdefghijklmnopabcdefghijklmnop
```

Each id allows exactly two things:

* The sign-in return address `https://<id>.chromiumapp.org/callback`, which Chrome reserves for that extension.
* Cross-origin API requests from `chrome-extension://<id>`.

Both come from the id, so they cannot become inconsistent. If a sign-in names another extension or return address, it stops on an error page on your instance. The instance never redirects it.

1. Set the list to the builds you distribute.
2. After you change the list, restart the application server.

### What listing an id does, and what it does not

The list restricts routing. It names where a completed sign-in may return and which origin may call the API. It is **not** proof of which package runs. Extension ids and their public keys are public. Anyone can load a modified unpacked build with the same key and id.

The sign-in uses your own login providers in the user's browser. The extension has no client secret to steal. PKCE binds the one-time code to the extension instance that started the sign-in. The code is valid for one minute and works once. [Managed distribution](#deploy-it-to-your-users), not this list, controls which packages your users may run.

Do not list the development id (`ijkajblcbajjpjbknfgdiiiljipafiko`) on a production instance. It belongs to every contributor's local build, modified or not. No build you distribute uses it.

### Nothing changes at GitHub or GitLab

Your login providers stay unchanged. The extension opens your instance's normal sign-in page in a Chrome sign-in window. Your instance completes the provider sign-in on its own callback, as it does for the web app. Only then does it return the result to the extension. You do not register a new OAuth application or add a callback URL at a provider.

## Sessions

* **They are visible.** An extension sign-in appears beside web sessions in the user's session list under **User settings**. Its label is **Browser extension in Chrome on …**.

* **Every way of ending a session ends it.** All these actions end extension sessions with web sessions:

  <!-- -->

  * The user ends that session or signs out everywhere.
  * An instance admin forces a sign-out.
  * An account is deleted.
  * An instance admin is demoted.

* **They cannot outlive the sign-in.** An extension session ends at the web session's absolute limit, however often it renews. `HEPHAESTUS_AUTH_SESSION_MAX_LIFETIME` sets that limit to seven days by default. `HEPHAESTUS_AUTH_ACCESS_TTL` sets the access token lifetime to 24 hours by default. The server checks revocation on every request. Chrome keeps the credentials in memory, so closing Chrome signs the extension out sooner.

* **Reuse of a renewal secret ends the session.** Each renewal replaces the extension's renewal secret. If the server receives an older secret again, it ends the whole extension session. It records the event in the authentication audit log. The user signs in again. A copied secret becomes detectable only when the copy or extension presents a secret the other has already replaced.

* **Consent still applies.** If a user has not completed web app setup, the extension sends them back before it shows anything. This includes acceptance of the current notice.

[Session deadlines](/admin/configuration-readiness.md#session-deadlines) explains the limits and how to choose them.

## Rate limits

Sign-in starts have the same per-address limit as other sign-ins. `HEPHAESTUS_AUTH_RATE_LIMIT_OAUTH_CAPACITY` per `HEPHAESTUS_AUTH_RATE_LIMIT_OAUTH_PERIOD` defaults to 20 a minute. Sign-in code redemption, session renewal, and sign-out share a separate per-address limit. `HEPHAESTUS_AUTH_RATE_LIMIT_CLIENT_SESSION_CAPACITY` per `HEPHAESTUS_AUTH_RATE_LIMIT_CLIENT_SESSION_PERIOD` defaults to 30 a minute. Everyone behind one network address shares that limit. For a campus or company network where everyone signs in together, increase it.

Users confirm review requests in the extension's own window. The extension sends them to the web app's endpoints, with the same permissions, cooldowns, and rate limits. A refusal uses your instance's words. Feedback approval and rejection stay in the web app.

## Deploy it to your users

Distribution depends on how users' Chrome installations are managed:

* **Unmanaged Chrome.** Users load your unpacked build from `chrome://extensions` with **Developer mode** on. Chrome labels it as unpacked. It does not update itself. Some organizations disable developer mode.
* **Managed Chrome.** [`ExtensionInstallForcelist`](https://chromeenterprise.google/policies/#ExtensionInstallForcelist) installs an extension for every managed profile. Each entry has an extension id and update address. An off-store package must be a signed `.crx` that you host with an update manifest. See [self-hosting](https://developer.chrome.com/docs/extensions/how-to/distribute/host-on-linux). Chrome accepts off-store force-installs only on machines that meet its management requirements. For example, Windows and macOS require a domain-joined, MDM-managed, or cloud-enrolled browser. This does not work on every desktop.
* **Restricting where it runs.** The [`ExtensionSettings`](https://chromeenterprise.google/policies/#ExtensionSettings) policy's `runtime_blocked_hosts` removes sites from the extension's reach, even with user permission. Its `runtime_allowed_hosts` makes exceptions to a broader block.

Before you plan managed distribution, check the policy documentation for your platforms. After Chrome Web Store publication, the store id and update address replace your own package. The same policies apply. Users still choose which provider sites the extension may read, one site at a time. Your instance address is the only other site it contacts.

### Provider addresses

The extension supports GitHub.com and GitLab, including self-hosted GitLab. It requests access to each provider address separately. A user allows `https://gitlab.example.org` the same way as `https://gitlab.com`. Your instance matches the page against the configured workspace connection for that address. Work on a provider that no workspace connects to appears as not available. GitHub Enterprise Server has no end-to-end verification and is not currently supported by this extension setup.

## Verify the setup

1. Ask your instance whether it accepts an id:

   ```
   curl "https://<APP_HOSTNAME>/api/auth/client/configuration?clientId=<extension id>"
   ```

   `{"registered":true}` means the id is in the list. `{"registered":false}` means it is not.

2. If the id is absent, check that the variable reached the application server.

3. Check that the server restarted.

4. Sign in from the extension's options page.

5. Confirm the session appears in your session list as **Browser extension in Chrome on …**.

## What the extension sends

After a user allows a provider site, the extension sends your instance the canonical address of each supported work page they open there. Supported work includes pull requests, merge requests, and issues. It sends the address when the page opens, and again while the page stays open and its review may change. On a repository's list, it sends a row's work address only when the user presses that row's Hephaestus button. It sends no page content and looks up no other page.

The extension does not read cookies. Its API calls use its own session, not browser cookies. Sign-in uses the user's normal Chrome profile. An existing provider or instance sign-in may be reused there, exactly as for the web app. Your instance resolves the address against data it already synchronized for the user's workspace. It makes no provider request to resolve it.

The report shows no feedback text. The listed comments contain no feedback text in the report, which links to them on the provider. Everything the report shows stays inside the extension-origin frame. A link to the web app opens a separate web session and may require sign-in there.
