Skip to content

[Portal] Framework-first Create Application wizard#5737

Draft
fungc-io wants to merge 55 commits into
authgear:mainfrom
fungc-io:fungc-io/dev-2392-create-application-framework-first-wizard
Draft

[Portal] Framework-first Create Application wizard#5737
fungc-io wants to merge 55 commits into
authgear:mainfrom
fungc-io:fungc-io/dev-2392-create-application-framework-first-wizard

Conversation

@fungc-io
Copy link
Copy Markdown
Member

Summary

Replaces the type-first "Create Application" screen with a framework-first wizard and builds out Quick Start tabs per client kind. The portal's OAuth-app management UX is redesigned around what the user is building (React, Django, iOS, etc.) instead of OAuth taxonomy.

Backend

  • New optional x_framework field on OAuthClientConfig (pkg/lib/config/oauth.go). JSON-schema enum of allowed framework ids. Nullable, additive, no migration needed. The auth server never branches on this field — it's a portal-only label.

Portal — Create flow

  • Apps-list header now exposes a split button: Application → new framework wizard at /configuration/apps/add, Machine-to-Machine → extracted M2M flow at /configuration/apps/add-m2m.
  • New wizard renders a framework grid (Website + Mobile · Desktop sections) using ChoiceButton tiles (consistent with Login Methods). Picking a server framework reveals an inline Stage 2 ("OIDC tokens" / "Cookie session via reverse proxy") — defaults to OIDC tokens with the nginx docs link clickable below.
  • Frameworks → application-type mapping is encapsulated in frameworks.ts via resolveType(stage2?). Submitting writes both x_application_type and x_framework.
  • On success the wizard deep-links to …/edit?tab=quick-start.

Portal — App details

  • New header above the tabs: framework icon, name, type + monospaced client ID with copy.
  • Apps-list redesigned: each row shows the framework icon, name, and a Type · Framework subline.
  • Settings tab: visual separators between sections; the Cookie-based authentication note is hidden for non-cookie clients.

Portal — Quick Start tab

A new tab for every framework-typed client (spa / traditional_webapp / native / confidential), in addition to the existing M2M Quick Start.

  • Shows the selected framework with a Change framework dialog (same ChoiceButton grid as the create wizard, filtered to same-type frameworks). Changes save on Apply via saveWithState.
  • Cookie SSO clients get an nginx-specific tutorial body and a Read user session in your code code snippet per framework (Express / Flask / Laravel / Java Spring Boot / ASP.NET Core MVC), with copy buttons.
  • "Other OIDC/SAML compatible" gets a dedicated panel with Client ID, Client Secret (with Reveal / copy), OpenID scope, and the OIDC endpoints (Login / Userinfo / Token / End Session / JWK Set).
  • SAML tab is hidden for OIDC-only confidential frameworks (Express / Flask / Laravel / Java / ASP.NET); kept for legacy and other-oidc clients.
  • Type-label rename in i18n only: "Single Page Application" → "Public Client", "Traditional Web Application" → "Cookie SSO", "OIDC/SAML Client Application" → "Confidential Client". Enum values unchanged.

Misc fixes / polish

  • Wizard auto-focuses the Name input on load.
  • Empty-state on Quick Start (no framework set) redesigned as a centered card.
  • Responsive framework grid: repeat(auto-fill, minmax(240px, 1fr)) so columns reflow on narrow viewports.
  • Express moved from the SPA cluster to the server cluster in the catalog order.

ref DEV-2392

Related: DEV-2532 (richer per-framework Quick Start content) — out of scope here.

Test plan

  • Backend: `go test ./pkg/lib/config/`
  • Backend: `go build ./...`
  • Portal: `npm run typecheck`
  • Portal: `npx jest` (168 tests across 27 suites)
  • Manual — split button menu shows both Application and Machine-to-Machine options
  • Manual — SPA framework (React) → no Stage 2; submits with `x_application_type=spa`, `x_framework=react`
  • Manual — Server framework (Flask, Java, ASP.NET) → Stage 2 visible, OIDC tokens preselected
  • Manual — Stage 2 OIDC tokens → `confidential`; Cookie SSO → `traditional_webapp`; switching framework clears Stage 2 silently
  • Manual — Reserved/duplicate name → inline error
  • Manual — Submit lands on `…/edit?tab=quick-start`
  • Manual — Quick Start tab visible for spa / traditional_webapp / native / confidential / m2m
  • Manual — Change framework dialog (filtered per type) → Apply saves immediately
  • Manual — Cookie SSO client: tutorial points at `/backend-api/nginx`, per-framework code snippet renders with copy
  • Manual — Other OIDC/SAML compatible: OIDC endpoints panel renders with Reveal button on Client Secret
  • Manual — Confidential + per-framework: SAML tab hidden; confidential + other-oidc or legacy: SAML tab shown
  • Manual — Apps list redesign: icon + Type · Framework subline; M2M uses server icon

🤖 Generated with Claude Code

fungc-io and others added 30 commits May 20, 2026 15:08
Additive, nullable. JSON schema enum lists allowed framework IDs.
No behavior change; field is a label used by the portal.

ref DEV-2392
ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Behavior unchanged. Route wired in the next commit.

ref DEV-2392
Replaces the type-first ChoiceGroup with a framework grid and an
inline Stage-2 callout for server-side frameworks. Submits the
chosen framework as x_framework alongside the resolved
x_application_type. M2M flow extracted to its own screen in a
previous commit.

ref DEV-2392
ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
constructConfig was called on every render via useMemo, but threw
when the user had not yet picked a framework — crashing the screen
on initial mount. Return the input config unchanged in that state
so the form stays clean until the user makes a selection.

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirror the constructConfig guard: a server framework selected
without a stage-2 choice would still crash via resolveType. Return
undefined so no secret instruction is emitted until the user has
completed the Stage 2 selection.

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reuses the same FluentUI CompoundButton-based ChoiceButton used by
the Login Methods authentication selectors (Passwordless / Enter
password). Visual treatment of selected/unselected states matches
the rest of the portal automatically.

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The checked ChoiceButton draws a 1px outline outside its
border-box. Without padding on the grid, that outline gets clipped
against the parent's overflow boundary on the outermost cards
(React, Angular, Next.js, Other SPAs).

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drop the 16 placeholder SVG files and switch the catalog from
file-import logos to Tabler glyph names (already loaded in the
portal via the iconfont). The visual style now matches
LoginMethodIcon and other Tabler usages in the portal.

Frameworks without a Tabler brand glyph fall back to a closely
related icon:
- express -> brand-javascript
- other-spa -> world-www
- java -> coffee
- aspnet -> brand-windows
- other-oidc -> shield-check
- ionic -> device-mobile

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Restore the original gating: only M2M clients show the Quick Start
tab. The wizard's post-create ?tab=quick-start URL still works for
M2M; for other types the query value is invalid and usePivot falls
back to Settings — which is the desired behavior until DEV-2532
fills in framework-specific Quick Start content for SPA / native /
confidential / traditional_webapp.

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Framework column reads from x_framework via the catalog and
shows the framework display name (e.g. "React", "Python (Django)").
For legacy apps without x_framework, or for M2M clients, it falls
back to the application-type label so the cell is never empty.

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drop the custom 15px font-size in FrameworkGrid section labels and
the AuthMethodChoice question. Both now use WidgetSubtitle (Text
variant 'medium', fontWeight 600) to match the rest of the portal.

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Type column is preserved; Framework appears next to it. For apps
without x_framework set, Framework cell shows '—'. The mobile
ClientCard appends the framework after the type (e.g. 'SPA · React').

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- spa: 'Single Page Application' -> 'Public Client'
- traditional_webapp: 'Traditional Web Application' -> 'Cookie SSO'
- confidential: 'OIDC/SAML Client Application' -> 'Confidential Client'

The enum values stay unchanged; only the user-facing labels are
adjusted. 'Single Page Application' was misleading for hybrid
frameworks like Next.js (server actions). 'Traditional Web
Application' was misleading because the actual semantics are
specifically cookie-based SSO via reverse proxy. The OAuth-correct
terms (public/confidential client) match the actual behavior.

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
fungc-io and others added 25 commits May 20, 2026 15:59
Each framework now carries its quick-start guide URL. Used by the
Quick Start widget to deep-link directly to the relevant framework
guide instead of asking the user to pick from a list.

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Each row's first cell now shows the framework's Tabler icon (or a
generic app-window glyph when no framework is set; server glyph for
M2M) on the left, the application name on top, and the type plus
framework label as a subline (e.g. 'Native App · Android').

The separate Type column is folded into the subline. Columns are
now: Name (icon + 2-line content) | Client ID | Action.

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The standalone Quickstart sidebar (with framework documentation
links) is removed from the Settings tab. The standalone Quick Start
pivot tab (M2M apps) is unchanged and now deep-links to the chosen
framework's guide when known. A redesigned Quick Start tab will
replace this in DEV-2532.

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Returns the Tabler icon name for a client based on x_framework
(framework-specific glyph), or a per-type fallback (server for M2M,
app-window otherwise). Shared between apps list and header.

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Breadcrumb: 'Applications > {ClientName}' -> 'Applications > Application Details'
- New header above the tabs: framework icon + name + type/client-ID line
- Uses the same icon resolver as the apps list

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Subsequent section titles (Client Secrets, URIs, Endpoints, Refresh
Token, Access Token, etc.) gain a top border + extra spacing so the
hierarchy is easier to scan. Basic Info — the first section — is
unchanged.

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The section is now shown only for traditional_webapp (which uses
cookie SSO via reverse proxy) and the legacy third_party_app type.
Confidential clients are token-based, so the cookie-session note
was misleading and contributed visual noise. Unspecified-type
fallback removed as well — if the type is unknown, the cookie
settings link is still accessible from project-level navigation.

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Renders a blocking dialog over the M2M create screen when there are
zero API resources. The dialog points the user to the Create API
Resource page. Cancel returns to the apps list.

The check runs on the screen itself so it covers both menu-driven
navigation (split-button on apps list) and direct URL navigation to
/configuration/apps/add-m2m. Restores the gate that the legacy
type-first create form had before the wizard redesign.

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ApplicationResourcesList relies on a parent flex container with
bounded height; in CreateM2MClientScreen the chain didn't provide
that, so the list collapsed to 0px. Wrapping the list in a
fixed-min-height flex container restores the table.

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The 'Go to the API Resource' link was rendered with react-router-dom's
Link inside a FluentUI Text, which strips link styling. Switch to
the portal's wrapped Link component which preserves FluentUI link
appearance even inside Text.

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
For spa clients, the Quick Start pivot tab is now visible. The tab
shows the currently-selected framework with an inline 'Change
framework' button that opens a dialog of SPA-compatible frameworks
(React, Vue, Angular, Next.js, Other SPAs) using the same
ChoiceButton-based FrameworkCard as the Create Application wizard.
Picking another framework saves immediately via the form's
saveWithState.

Below the framework row, a 'Step-by-step Guide' card links to the
framework's documentation (framework.docLink in the catalog).
Next.js now points at /regular-web-app/nextjs.

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Quick Start tab now owns framework selection for spa clients
via the Change framework dialog. The Settings tab no longer carries
the Framework dropdown to avoid two ways to do the same thing.

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Generalize the SPA Quick Start into a framework-agnostic Quick Start
component for any client type that selects a framework. Cookie SSO
clients (traditional_webapp) now also get the Quick Start pivot tab,
with the framework picker filtered to cookie-compatible frameworks
(Express.js, Django, Laravel, Java, ASP.NET).

The tutorial card overrides the doc link and body for Cookie SSO:
- Doc link: https://docs.authgear.com/get-started/backend-api/nginx
- Body: 'set up nginx as a reverse proxy with Authgear in front of
  your {framework} app' instead of the generic SDK-based message

Files renamed: EditOAuthClientFormSPAQuickStart -> ...FrameworkQuickStart.

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Same FrameworkQuickStart component as spa/traditional_webapp; the
catalog already carries per-framework doc links for the native
mobile guides (react-native/ios/android/flutter/ionic) and the
regular-web-app guides plus oidc-provider for confidential.

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Rename Python (Django) -> Python (Flask) since Authgear's docs only
  ship a Flask guide for Python. Framework id renamed django -> flask
  in both portal catalog and backend JSON schema enum.
- Update per-framework doc URLs to the correct deep-link pages from
  https://docs.authgear.com/get-started/regular-web-app:
    - express   -> regular-web-app/express
    - flask     -> regular-web-app/python-flask-app
    - laravel   -> regular-web-app/laravel
    - java      -> regular-web-app/java-spring-boot (display: Java
                   (Spring Boot))
    - aspnet    -> regular-web-app/asp.net-core-mvc (display: ASP.NET
                   Core MVC)
- Confidential clients don't use the Authgear SDK; they use standard
  OIDC libraries. Add a confidential-specific tutorial body and a
  separate body for the 'Other OIDC/SAML compatible' option.
- Update tests and Storybook stories for the rename.

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Below the tutorial card on Cookie SSO clients, render a 'Read user
session in your code' section with a language-labelled code snippet
showing how that framework reads the x-authgear-* headers nginx
forwards from the Authgear resolver.

Snippets included for Express.js, Python (Flask), PHP (Laravel),
Java (Spring Boot), and ASP.NET Core MVC. Headers used:
X-Authgear-Session-Valid and X-Authgear-User-Id (from the docs
example at /get-started/backend-api/nginx).

Each snippet card has a language pill and a copy button (uses the
existing useCopyFeedback hook).

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
For confidential clients with x_framework=other-oidc, replace the
generic Step-by-step Guide card with a dedicated 'Use Authgear as
an OpenID Connect Provider' section listing the integration values
the user needs to plug into a standard OIDC library:

- Client ID
- Client Secret Key (masked, with Reveal eye button that triggers
  startReauthentication; once revealed the eye becomes the copy
  button)
- OpenID Scope (recommended scope string)
- Login / Userinfo / Token / End Session Endpoints
- JSON Web Key (JWK) Set

A 'guide' link in the description deep-links to the OIDC provider
docs.

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Default the Stage 2 auth method to 'OIDC tokens' when a server
  framework is picked in the Create Application wizard. Cookie SSO
  is still one click away, but most users don't want it. Removes
  the need to make a choice for the common case.

- Redesign the no-framework empty state on the Quick Start tab into
  a centered card (dashed border, tinted background, larger icon,
  centered text + CTA). The previous left-aligned layout looked
  half-finished.

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Auto-focus the Name input when /configuration/apps/add loads so
  the user can start typing immediately.
- Stop click propagation on the cookie 'See the nginx cookie auth
  guide' link so clicking the link opens the doc instead of
  swallowing into the radio's label and selecting Cookie SSO.

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The link was rendered inside the FluentUI ChoiceGroup's onRenderField,
which puts it inside the <label> that wraps the radio. Browsers fire
label-click for ANY descendant of a label regardless of React's
event propagation, so clicking the link was selecting the radio
instead of navigating. Render the link below the ChoiceGroup
instead.

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous FluentUI ChoiceGroup with custom onRenderLabel had
multi-line label rendering issues (radio dots overlapping the
title text). Switch to a plain <label><input type='radio'> markup
with manual layout:

- Each option shows a bold title and a one-line description below.
- No outer blue panel or nested card chrome — just the question
  header and the two radios stacked.
- The 'See the nginx cookie auth guide' link is rendered as a
  sibling outside the labels so it's clickable without bubbling
  into a label-click and selecting the radio.

Added i18n keys:
- stage2.option.token.description
- stage2.option.cookie.description

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Reorder the Website framework cards so Express.js sits with the
  other server frameworks (Flask, Laravel, Java, ASP.NET) instead
  of between Next.js and Other SPAs. SPA cluster (React/Vue/Angular/
  Next.js/Other SPAs) now comes first, then server cluster, then
  Other OIDC/SAML compatible.
- Switch the grid from fixed 3 columns to
  repeat(auto-fill, minmax(240px, 1fr)) so columns reflow to 2 or 1
  on narrow viewports. Previously the helper text was clipped on
  medium screens because columns were too narrow for the secondary
  text. The FrameworkCard now fills the grid cell width fully.

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
For confidential clients whose framework is one of the per-framework
OIDC integrations (Express, Flask, Laravel, Java, ASP.NET), the
user is doing OIDC integration, not SAML. Hide the SAML tab to
reduce noise. The tab still shows for:

- legacy confidential clients with no x_framework set
- Other OIDC/SAML compatible (x_framework == 'other-oidc')

Any saved SAML config is preserved in the YAML — hidden, not
removed. Switching back to other-oidc surfaces it again.

ref DEV-2392

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Move @typescript-eslint type-aware rules into a TS-only config block
  that declares the plugin, so ESLint 9 can resolve the plugin scope.
- Drop redundant tc := tc loop alias to satisfy go fix -omitzero=false.
- Hoist Text styles consts to module scope to fix no-use-before-define.
- Merge duplicate EditOAuthClientForm imports.
- Add /* global module */ to fileMock and remove ui-monospace font name.
- Prettier formatting touch-ups across the changed files.
@tung2744
Copy link
Copy Markdown
Contributor

@fungc-io Should I review this?

@fungc-io fungc-io marked this pull request as draft May 27, 2026 12:54
@fungc-io
Copy link
Copy Markdown
Member Author

@tung2744 , no, it's still in progress, i've changed it to draft
Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants