Close ORCID shared-auth frontend gap

This commit is contained in:
axiomlogicnexus 2026-06-29 13:40:23 +00:00
parent 3ccfe617ab
commit 4dfdd38d0b
8 changed files with 153 additions and 4 deletions

1
.gitignore vendored
View file

@ -11,6 +11,7 @@ Content/Browser/dist/
Content/Browser/node_modules/
website/dist/
website/node_modules/
website/test-results/
website/server/node_modules/
website/server/data/
tools/sentrux/bin/*

View file

@ -90,6 +90,10 @@ Current behavior:
- email/password login and registration
- optional GitHub and Google OAuth flags
- optional ORCID now also exists as a bounded first-party auth-server custom-provider lane instead of remaining a client-only placeholder
- the browser client now also registers that ORCID lane through the supported
SuperTokens third-party recipe contract itself, so provider truth is not
stranded in server/runtime/UI parity while the sign-in recipe still omits the
provider at execution time
- deterministic local fallback mode when the backend is not configured
- bounded auth-health probing that now distinguishes configured, reachable, and ready shared-core posture without mutating auth state
- bounded frontend auth-env diagnostics that now warn when the browser lane still points at loopback, insecure `http`, or split backend/auth targets

View file

@ -1052,6 +1052,41 @@ Current audit note:
- `scripts/run-hypertwist-gitnexus-analyze.sh`
- `scripts/run-hypertwist-gitnexus-status.sh`
## Latest shared-auth frontend registration closure (`2026-06-29`)
- the last remaining ORCID shared-auth drift was then closed on the browser
client itself instead of stopping at server, env, and UI parity:
- `website/src/auth/supertokens-client.ts` now registers ORCID through the
supported SuperTokens third-party recipe contract by passing a bounded
custom-provider config object into `signInAndUpFeature.providers`
- HyperTwist no longer depends on a guessed runtime `Custom` export for that
lane, so the optional ORCID provider now matches the actual library
contract as well as the earlier product/docs posture
- the provider-builder helper remains isolated and testable, which keeps the
GitHub/Google ordering stable while adding ORCID only when the runtime flag
is intentionally enabled
- focused regression coverage now also exists in
`website/src/__tests__/supertokens-client.test.ts`
- the same-family validation truth stayed green after the closure under:
- `npm --prefix website run type-check`
- `npm --prefix website test -- --run src/__tests__/supertokens-client.test.ts src/__tests__/public-auth-pages.test.tsx src/__tests__/platform-auth.bootstrap.test.tsx`
- `3` test files passed
- `15` tests passed
- `scripts/run-hypertwist-web-surface-validation.sh`
- focused website route/auth/release suite: `14` files, `81` tests passed
- website/server suite: `10` files, `36` tests passed
- website and `Content/Browser` production audits stayed clean
- `scripts/run-hypertwist-sentrux-source-only.sh`
- `Quality: 6235`
- `All rules pass`
- `scripts/run-hypertwist-gitnexus-analyze.sh`
- `16,400` nodes, `38,759` edges, `675` clusters, `300` flows
- `scripts/run-hypertwist-gitnexus-status.sh`
- `Status: up-to-date`
- the packet also tightened routine worktree hygiene by treating
`website/test-results/` as ignore-only rebuildable runner residue alongside
the existing `TODO.json` scratch rule
## Latest protected auth/session authority follow-up (`2026-06-27`)
- the next same-family protected-shell continuation then brought the signed-in

File diff suppressed because one or more lines are too long

View file

@ -160,6 +160,7 @@ run_step \
src/__tests__/public-route-registry.test.ts \
src/__tests__/route-shells.test.tsx \
src/__tests__/release-manifest.test.ts \
src/__tests__/supertokens-client.test.ts \
src/__tests__/public-marketing-pages.test.tsx \
src/__tests__/public-auth-pages.test.tsx
run_step "website production build" npm --prefix website run build

View file

@ -71,6 +71,11 @@ manual:
- the homepage, docs, and resources surfaces now also share a route atlas that
explains what each major public page owns, so the site reads more like a
professional operator manual than a flatter brochure shell
- the shared-auth lane now also keeps its optional ORCID provider honest
end-to-end: the auth server owns the bounded provider, the same-origin
manifest emits matching runtime env truth, and the browser client registers
ORCID through the supported third-party recipe contract instead of only
exposing the provider in docs or button copy
- the about, feature-atlas, resources, and docs surfaces now also expose a
concrete shipped control-profile and settings roster for the desktop lane,
including the current `classic-wca-keyboard/v1` profile, scenic immersive
@ -322,6 +327,27 @@ Latest first-session quickstart/manual follow-up on `2026-06-27`:
- `scripts/run-hypertwist-gitnexus-status.sh`
- `Status: up-to-date`
Latest shared-auth ORCID frontend-closure follow-up on `2026-06-29`:
- the remaining browser-side ORCID provider drift is now closed end to end:
- `website/src/auth/supertokens-client.ts` now passes ORCID into the
SuperTokens third-party recipe as a bounded custom-provider config object
instead of depending on a guessed runtime helper export
- the helper remains isolated in
`buildEnabledThirdPartyProviders`, so GitHub/Google ordering stays stable
while ORCID is added only when intentionally enabled
- focused regression coverage now exists in
`src/__tests__/supertokens-client.test.ts`
- focused validation for that closure stayed green under:
- `npm --prefix website run type-check`
- `npm --prefix website test -- --run src/__tests__/supertokens-client.test.ts src/__tests__/public-auth-pages.test.tsx src/__tests__/platform-auth.bootstrap.test.tsx`
- `3` test files passed
- `15` tests passed
- the broader current website lane stayed green again under:
- `scripts/run-hypertwist-web-surface-validation.sh`
- website focused route/auth/release suite: `14` files, `81` tests passed
- website/server suite: `10` files, `36` tests passed
Current dependency-health truth from the `2026-06-23` hardening pass:
- `website/` production audit is clean

View file

@ -0,0 +1,41 @@
import { describe, expect, it, vi } from 'vitest'
import { buildEnabledThirdPartyProviders } from '../auth/supertokens-client'
describe('buildEnabledThirdPartyProviders', () => {
it('includes the bounded ORCID custom provider when that runtime flag is enabled', () => {
const githubInit = vi.fn(() => ({ id: 'github' }))
const googleInit = vi.fn(() => ({ id: 'google' }))
const providers = buildEnabledThirdPartyProviders({
githubEnabled: false,
googleEnabled: false,
orcidEnabled: true,
Github: { init: githubInit },
Google: { init: googleInit },
})
expect(providers).toEqual([{ id: 'orcid', name: 'ORCID' }])
expect(githubInit).not.toHaveBeenCalled()
expect(googleInit).not.toHaveBeenCalled()
})
it('preserves the built-in provider order while appending ORCID only when enabled', () => {
const githubProvider = { id: 'github' }
const googleProvider = { id: 'google' }
const orcidProvider = { id: 'orcid', name: 'ORCID' }
const providers = buildEnabledThirdPartyProviders({
githubEnabled: true,
googleEnabled: true,
orcidEnabled: true,
Github: { init: () => githubProvider },
Google: { init: () => googleProvider },
})
expect(providers).toEqual([
githubProvider,
googleProvider,
orcidProvider,
])
})
})

View file

@ -3,6 +3,7 @@ import { PASSWORD_POLICY_HINT, PASSWORD_POLICY_PLACEHOLDER, validateStrongPasswo
import {
isGitHubOAuthEnabled,
isGoogleOAuthEnabled,
isOrcidOAuthEnabled,
isSuperTokensConfigured,
SUPERTOKENS_API_BASE_PATH,
SUPERTOKENS_API_DOMAIN,
@ -81,6 +82,42 @@ type SuperTokensFormInput = {
type SuperTokensThirdPartyId = 'github' | 'google' | 'orcid'
type SuperTokensCustomProviderConfig = {
id: string
name: string
}
type BuiltInProviderFactory<TProvider> = {
init: () => TProvider
}
export function buildEnabledThirdPartyProviders<TProvider>({
githubEnabled,
googleEnabled,
orcidEnabled,
Github,
Google,
}: {
githubEnabled: boolean
googleEnabled: boolean
orcidEnabled: boolean
Github: BuiltInProviderFactory<TProvider>
Google: BuiltInProviderFactory<TProvider>
}) {
const thirdPartyProviders: Array<TProvider | SuperTokensCustomProviderConfig> = []
if (githubEnabled) thirdPartyProviders.push(Github.init())
if (googleEnabled) thirdPartyProviders.push(Google.init())
if (orcidEnabled) {
thirdPartyProviders.push({
id: 'orcid',
name: 'ORCID',
})
}
return thirdPartyProviders
}
export async function ensureSuperTokensInit() {
if (initialized || !isSuperTokensConfigured() || typeof window === 'undefined') {
return
@ -102,9 +139,13 @@ export async function ensureSuperTokensInit() {
const { default: ThirdParty, Github, Google } = thirdPartyModule
const thirdPartyProviders = []
if (isGitHubOAuthEnabled()) thirdPartyProviders.push(Github.init())
if (isGoogleOAuthEnabled()) thirdPartyProviders.push(Google.init())
const thirdPartyProviders = buildEnabledThirdPartyProviders({
githubEnabled: isGitHubOAuthEnabled(),
googleEnabled: isGoogleOAuthEnabled(),
orcidEnabled: isOrcidOAuthEnabled(),
Github,
Google,
})
const recipeList: Parameters<typeof SuperTokens.init>[0]['recipeList'] = [
EmailPassword.init({