Tested against ghcr.io/quackbackio/quackback:main at digest sha256:b6edc570a72952b00c35d818901044f102965ca0d94069506a8960e40aa0d286, pulled 2026-09-08, carrying #373, #508, #509, #510 and #514.
Summary
Everything #337 asked for works. EVE Online now signs in end to end: identity resolves from the access-token JWT, a placeholder address is minted, and the admin "Test sign-in" passes and unlocks the enforcement gate.
One thing is left, and it is small: the admin editor renders openid as an unremovable scope, so a provider that rejects openid cannot be configured through the UI at all. I had to write the scope with SQL to complete the test. There is a workaround detailed below that allows me to use Quackback as it ships today.
The problem
EVE Online's authorize endpoint rejects openid outright:
{"error":"invalid_scope","error_description":"The requested 'openid' scope is not valid."}
openid is not one of its scopes. Its discovery document is served at https://login.eveonline.com/.well-known/openid-configuration and publishes scopes_supported: null, so nothing warns the admin in advance.
A new provider starts at DEFAULT_OIDC_SCOPES (oidc-scopes.ts:17), which is ['openid','email','profile']. In the editor, the openid token renders with the label required and no remove control:
{scope === REQUIRED_OIDC_SCOPE ? (
<span className="text-[11px] text-muted-foreground">required</span>
) : (
<button aria-label={`Remove scope ${scope}`} …>×</button>
)}
advanced-section.tsx:122-127. supportedSubset (oidc-scopes.ts:74) also keeps openid regardless of what the IdP advertises, so the one-click "fix to supported scopes" path cannot remove it either.
The result is that no sequence of clicks reaches a working configuration for such a provider. Every authorize request carries openid and fails at the IdP before the user ever returns.
Where the restriction is and isn't
It is only in the editor. Both layers below accept any scope set:
sso.ts:228 validates the field as scopes: z.string().max(512).nullable().optional().
effectiveScopes (oidc-scopes.ts:39) returns the stored value verbatim whenever it parses to a non-empty set.
So the workaround is a direct write:
update identity_provider
set scopes = 'publicData'
where registration_id = '<registrationId>';
After that the editor prefills from the stored value and renders publicData alone, with a working × and no openid — the restriction only bites on the way out of the default set. I did not test whether pressing Save connection from that state round-trips the value intact.
Possible fix
Allowing openid to be removed seems sufficient. The comment at advanced-section.tsx:5-9 explains the current behaviour as protecting an admin from breaking OIDC by accident, which is fair — but a warning would serve that as well as a hard block, and would not exclude providers that are OAuth-shaped rather than OIDC-shaped.
REQUIRED_OIDC_SCOPE in supportedSubset would want the same treatment, otherwise "fix to supported scopes" silently reintroduces it.
There is a second, larger question you may or may not want to answer: effectiveScopes treats an empty or whitespace scope string as "use the defaults", so there is no way to express "send no scope parameter at all". EVE accepts that form — an authorization-only application with no scopes granted reaches character selection with no scope in the query string. That is a separate design decision from the unremovable openid, and only the first one blocked me, so I mention it only for completeness.
Verification that the rest works
With scopes = 'publicData' and this mapping:
{"profile":{"sources":["accessTokenJwt"],"claims":{"id":"sub","name":"name"},"allowMissingEmail":true}}
Portal sign-in completed and created:
user name snipereagle1
email sso-oidc-<id>-<hex>@anon.quackback.io
email_verified false
account provider_id oidc_<id>
account_id CHARACTER:EVE:1107376792
has_id_token false
has_access_token true
has_id_token = false alongside a resolved account_id is the interesting part: EVE returns no ID token at all, and identity came from the access-token JWT.
Test sign-in passed and stamped the gate — sso test succeeded; provider gates unlocked. The reported stages were state validation, discovery fetch, token exchange, account identifier resolved from accessTokenJwt, display name resolved from accessTokenJwt, no avatar released, and no email released with a placeholder to be created. No id-token-decode or signature-verify rows appeared, which is the hasIdToken guard at sso-test-handshake.ts:345 doing its job — that was limitation 1 in #337 and it is now gone.
The stored last_test_capture recorded the provenance directly:
"identity": {
"id": "CHARACTER:EVE:1107376792",
"name": "snipereagle1",
"paths": { "id": "sub", "name": "name" },
"sources": { "id": "accessTokenJwt", "name": "accessTokenJwt" }
}
Reproducing without an EVE account
An EVE developer application needs an account with game time, so this may not be directly reproducible on your side. The behaviour does not depend on EVE, though — any OAuth provider that rejects openid, or any test double whose authorize endpoint 400s on it, reproduces the editor problem exactly. The configuration under test was:
discovery_url https://login.eveonline.com/.well-known/openid-configuration
scopes publicData
prompt (default: login)
claim_mapping {"profile":{"sources":["accessTokenJwt"],
"claims":{"id":"sub","name":"name"},
"allowMissingEmail":true}}
Tested against
ghcr.io/quackbackio/quackback:mainat digestsha256:b6edc570a72952b00c35d818901044f102965ca0d94069506a8960e40aa0d286, pulled 2026-09-08, carrying #373, #508, #509, #510 and #514.Summary
Everything #337 asked for works. EVE Online now signs in end to end: identity resolves from the access-token JWT, a placeholder address is minted, and the admin "Test sign-in" passes and unlocks the enforcement gate.
One thing is left, and it is small: the admin editor renders
openidas an unremovable scope, so a provider that rejectsopenidcannot be configured through the UI at all. I had to write the scope with SQL to complete the test. There is a workaround detailed below that allows me to use Quackback as it ships today.The problem
EVE Online's authorize endpoint rejects
openidoutright:{"error":"invalid_scope","error_description":"The requested 'openid' scope is not valid."}openidis not one of its scopes. Its discovery document is served athttps://login.eveonline.com/.well-known/openid-configurationand publishesscopes_supported: null, so nothing warns the admin in advance.A new provider starts at
DEFAULT_OIDC_SCOPES(oidc-scopes.ts:17), which is['openid','email','profile']. In the editor, theopenidtoken renders with the labelrequiredand no remove control:advanced-section.tsx:122-127.supportedSubset(oidc-scopes.ts:74) also keepsopenidregardless of what the IdP advertises, so the one-click "fix to supported scopes" path cannot remove it either.The result is that no sequence of clicks reaches a working configuration for such a provider. Every authorize request carries
openidand fails at the IdP before the user ever returns.Where the restriction is and isn't
It is only in the editor. Both layers below accept any scope set:
sso.ts:228validates the field asscopes: z.string().max(512).nullable().optional().effectiveScopes(oidc-scopes.ts:39) returns the stored value verbatim whenever it parses to a non-empty set.So the workaround is a direct write:
After that the editor prefills from the stored value and renders
publicDataalone, with a working×and noopenid— the restriction only bites on the way out of the default set. I did not test whether pressing Save connection from that state round-trips the value intact.Possible fix
Allowing
openidto be removed seems sufficient. The comment atadvanced-section.tsx:5-9explains the current behaviour as protecting an admin from breaking OIDC by accident, which is fair — but a warning would serve that as well as a hard block, and would not exclude providers that are OAuth-shaped rather than OIDC-shaped.REQUIRED_OIDC_SCOPEinsupportedSubsetwould want the same treatment, otherwise "fix to supported scopes" silently reintroduces it.There is a second, larger question you may or may not want to answer:
effectiveScopestreats an empty or whitespace scope string as "use the defaults", so there is no way to express "send noscopeparameter at all". EVE accepts that form — an authorization-only application with no scopes granted reaches character selection with noscopein the query string. That is a separate design decision from the unremovableopenid, and only the first one blocked me, so I mention it only for completeness.Verification that the rest works
With
scopes = 'publicData'and this mapping:{"profile":{"sources":["accessTokenJwt"],"claims":{"id":"sub","name":"name"},"allowMissingEmail":true}}Portal sign-in completed and created:
has_id_token = falsealongside a resolvedaccount_idis the interesting part: EVE returns no ID token at all, and identity came from the access-token JWT.Test sign-in passed and stamped the gate —
sso test succeeded; provider gates unlocked. The reported stages were state validation, discovery fetch, token exchange, account identifier resolved fromaccessTokenJwt, display name resolved fromaccessTokenJwt, no avatar released, and no email released with a placeholder to be created. Noid-token-decodeorsignature-verifyrows appeared, which is thehasIdTokenguard atsso-test-handshake.ts:345doing its job — that was limitation 1 in #337 and it is now gone.The stored
last_test_capturerecorded the provenance directly:Reproducing without an EVE account
An EVE developer application needs an account with game time, so this may not be directly reproducible on your side. The behaviour does not depend on EVE, though — any OAuth provider that rejects
openid, or any test double whose authorize endpoint 400s on it, reproduces the editor problem exactly. The configuration under test was: