Skip to main content
A plugin can sign a user in with OAuth 2.0, then list which of its installations and repositories that user can use. Your plugin is its own OAuth client: it authenticates with the keys it already registered, and needs no client secret. The user’s token tells you who the user is and what they can reach. It doesn’t let you act. To read code or report checks, you still mint an access token for the installation with your plugin JWT.

What you need

  • OAuth redirect URIs. Ask your Entire contact to add up to 10 HTTPS OAuth redirect URIs when you register your plugin, or later. Entire compares them character for character. Without them, your plugin isn’t an OAuth client.
  • Your client ID, which Entire gives you when it adds the OAuth redirect URIs. It looks like plugin_01M5.... It never changes, isn’t a secret, and doesn’t depend on your slug.
  • Your plugin’s key, the same one you sign plugin JWTs with.

Sign the user in

Sign-in is the authorization code flow, with PKCE required. Send the user to auth.entire.io, which forwards them to the Core that holds their account:
The first time, the user approves your plugin on a consent page that shows your name and logo. Later sign-ins skip the page until the user revokes it. Core then redirects to your redirect_uri with code, state and iss (RFC 9207). iss names the Core that issued the code, such as https://eu.auth.entire.io. Check that it’s one of Entire’s Cores.
  • Core refuses a request without a PKCE challenge, and a request with a resource parameter.
  • scope must be present, but Core ignores its value. Every plugin gets openid offline_access.
  • Tie state to the browser session that started the sign-in, and check it on the redirect.

Redeem the code

Redeem the code at the Core named by iss. auth.entire.io has no token endpoint. Authenticate with a client assertion (RFC 7523) in place of a client secret:
The assertion is a JWT signed with your plugin’s key: The response carries access_token, id_token and refresh_token. To refresh, send grant_type=refresh_token and the refresh token to the same Core, with a new assertion. Refresh tokens rotate: each refresh returns a new one, so store the latest. Only the token endpoint accepts the assertion. Basic auth and a missing assertion answer 401 invalid_client.

What the tokens contain

The access token’s audience is entire:plugin-api, so it works only on the user routes below. Every other /api/v1 route refuses it. /userinfo returns only sub, preferred_username and handle. Treat provider and provider_user_id as opaque.

List what the user can use

Two routes take the user’s access token as bearer token, on any Core. First, your active installations in projects the user can read:
repository_selection is all or selected. Then the installation’s repositories that the user can pull:
Both take per_page, from 1 to 100, default 30. While the response has a next_cursor, pass it back as ?cursor= for the next page. The last page has no next_cursor. A repositories page can be short, or empty, while next_cursor is still set, because Entire filters each page for the user. Keep paging until there’s no cursor. If the installation changes during the walk, you get 409 conflict: start again from the first page. The list leaves out installations the user reaches only through grants on single repositories, without read access to the project.

Act for the user

  1. Sign the user in, and list the installations and repositories they can use.
  2. Let the user pick a repository from that list.
  3. Mint an access token for that installation with your plugin JWT, scoped to the repository.
  4. Before each later action you take for the user, check their access through the user routes again.

When access ends

A user’s tokens can stop working before they expire, and refreshes can fail. For example:
  • The user revokes your plugin. Their next sign-in shows the consent page again.
  • The user’s account is suspended or removed.
  • Your OAuth redirect URIs are removed. New sign-ins fail too.
A 401 with detail “the account is not active” means the user lost access. Don’t retry it; ask the user to sign in again.

Which Core to call

Start every sign-in at auth.entire.io, not at a specific Core such as https://eu.auth.entire.io: it forwards the user to the Core that holds their account. Redeem and refresh at the Core named by iss, and set the assertion’s aud to it. The user routes accept the token on any Core. Your client ID and keys work on every Core.

Errors

These are for the user routes. Error bodies are RFC 9457 problem documents, with a machine-readable code member.