Skip to content

feat(ui): add secret regeneration page and client credentials flow for user apps#121

Merged
appleboy merged 13 commits into
mainfrom
feat/user-app-regenerate-secret
Mar 21, 2026
Merged

feat(ui): add secret regeneration page and client credentials flow for user apps#121
appleboy merged 13 commits into
mainfrom
feat/user-app-regenerate-secret

Conversation

@appleboy
Copy link
Copy Markdown
Member

@appleboy appleboy commented Mar 21, 2026

Summary

  • Add dedicated UserAppSecret template for user-facing secret regeneration with proper title, security warning, and copy-to-clipboard button (previously reused the misleading "App Registered" page)
  • Handle GetClient error after regeneration with fallback to pre-loaded client
  • Add UserClientSecretPageProps type alias for self-describing template API
  • Enable Client Credentials Flow in user app form for confidential clients (previously admin-only)
  • Add EnableClientCredentialsFlow to UserUpdateClientRequest and update grant-type validation

Test plan

  • Login as regular user, create a confidential app
  • Go to app detail page and click "Regenerate Secret"
  • Verify the page shows "Client Secret Regenerated" title (not "App Registered!")
  • Verify no "Pending admin approval" notice appears
  • Verify "Copy to Clipboard" button works
  • Verify navigation links point to /apps/:id/edit, /apps/:id, and /apps
  • Create/edit a confidential app and enable Client Credentials Flow
  • Verify CC flow checkbox is disabled when client type is public
  • Verify a CC-only confidential client can be saved/updated without error
  • Run make test - all tests pass
  • Run make lint - 0 issues

Generated with Claude Code

- Add user_app_secret.templ with proper title, security warning, and copy-to-clipboard support
- Replace reuse of UserAppCreated template with dedicated UserAppSecret template in handler

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 21, 2026 09:35
@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 21, 2026

Codecov Report

❌ Patch coverage is 29.41176% with 60 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/handlers/user_client.go 0.00% 37 Missing ⚠️
internal/core/client_type.go 0.00% 16 Missing ⚠️
internal/handlers/client.go 0.00% 4 Missing ⚠️
internal/services/client.go 86.36% 1 Missing and 2 partials ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a dedicated UI page for user-owned app client-secret regeneration so the post-regeneration experience matches the admin flow and avoids the misleading “App Registered”/pending-approval messaging.

Changes:

  • Introduces UserAppSecret templ page to display the regenerated secret with security warning and copy-to-clipboard affordance.
  • Updates RegenerateAppSecret handler to render the new template instead of reusing UserAppCreated.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
internal/templates/user_app_secret.templ New dedicated secret-regeneration template for user apps (mirrors admin secret page UX).
internal/handlers/user_client.go Switches regenerate-secret handler to render UserAppSecret.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 296 to 300
templates.RenderTempl(
c,
http.StatusOK,
templates.UserAppCreated(templates.UserClientCreatedPageProps{
templates.UserAppSecret(templates.UserClientCreatedPageProps{
BaseProps: templates.BaseProps{CSRFToken: middleware.GetCSRFToken(c)},
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetClient is called after regenerating the secret and its error is ignored; if it fails (and returns nil), clientToDisplay will produce nil and the template render will likely panic when dereferencing props.Client. Handle the error (or fall back to the already-loaded client) before rendering the response.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,62 @@
package templates

templ UserAppSecret(props UserClientCreatedPageProps) {
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new UserAppSecret page uses UserClientCreatedPageProps, which is now misleading since it’s not only used for the post-create flow. Consider introducing a dedicated props type (e.g., UserClientSecretPageProps) or renaming the existing type to reflect both create and regenerate use cases to keep template APIs self-describing.

Suggested change
templ UserAppSecret(props UserClientCreatedPageProps) {
type UserClientSecretPageProps = UserClientCreatedPageProps
templ UserAppSecret(props UserClientSecretPageProps) {

Copilot uses AI. Check for mistakes.
appleboy and others added 2 commits March 21, 2026 17:41
- Handle GetClient error after regeneration with fallback to pre-loaded client
- Add UserClientSecretPageProps type alias for self-describing template API

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Show Client Credentials Flow checkbox in user app form for confidential clients
- Parse and pass EnableClientCredentialsFlow in CreateApp and UpdateApp handlers
- Add EnableClientCredentialsFlow to UserUpdateClientRequest
- Enforce confidential-only constraint in UserUpdateClient service method

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/services/client.go Outdated
Comment on lines +598 to +605
enableClientCredentials := req.EnableClientCredentialsFlow &&
client.ClientType == ClientTypeConfidential
client.EnableClientCredentialsFlow = enableClientCredentials
client.GrantTypes = buildGrantTypes(
req.EnableDeviceFlow,
req.EnableAuthCodeFlow,
enableClientCredentials,
)
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UserUpdateClient now supports EnableClientCredentialsFlow, but the function’s “at least one grant type” validation earlier still only considers device/auth-code. This makes it impossible to save/update a client configured with only Client Credentials (e.g., CC-only client created successfully will fail future updates). Update the validation to include req.EnableClientCredentialsFlow (and keep the confidential-only restriction) so it matches the grant-types rebuilding logic.

Copilot uses AI. Check for mistakes.
Comment on lines +23 to 24
ShowClientCredentials: true,
ScopePresetsOnly: true,
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes the user app form to expose Client Credentials Flow controls (ShowClientCredentials: true). That’s a functional behavior change (users can request/enable CC flow) and isn’t mentioned in the PR description/title, which frames this as only a dedicated secret-regeneration page. Either update the PR description to explicitly include this feature (and rationale/implications) or split it into a separate PR.

Copilot uses AI. Check for mistakes.
@appleboy appleboy changed the title feat(ui): add dedicated secret regeneration page for user apps feat(ui): add secret regeneration page and client credentials flow for user apps Mar 21, 2026
appleboy and others added 2 commits March 21, 2026 18:00
- Add EnableClientCredentialsFlow to the "at least one grant type" check
  in UserUpdateClient so CC-only confidential clients pass validation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@appleboy
Copy link
Copy Markdown
Member Author

@copilot review

Copy link
Copy Markdown

Copilot AI commented Mar 21, 2026

@appleboy I've opened a new pull request, #122, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +560 to 562
if !req.EnableDeviceFlow && !req.EnableAuthCodeFlow && !req.EnableClientCredentialsFlow {
return ErrAtLeastOneGrantRequired
}
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UserUpdateClient validates ErrAtLeastOneGrantRequired using the raw request flags, but later forces Client Credentials off for public clients. A crafted request like client_type=public + enable_client_credentials_flow=true (and other flows false) will pass validation but end up with no enabled grants/empty GrantTypes. Consider either (a) validating client-type/grant compatibility up front and returning an error when CC is requested for public clients, or (b) re-checking the final computed enable flags (EnableDeviceFlow || EnableAuthCodeFlow || enableClientCredentials) before saving.

Copilot uses AI. Check for mistakes.
- Add ErrClientCredentialsRequireConfidential validation in UserUpdateClient
  before computing grant types, preventing public+CC-only from saving with
  empty grants

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/services/client.go Outdated
Comment thread internal/services/client.go Outdated
- Normalize client type early in UserUpdateClient to avoid inconsistency
  between validation and persistence
- Add 3 tests: CC flow for confidential, CC rejected for public,
  CC-only confidential client

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/services/client.go
… admin UpdateClient

- Add upfront ErrClientCredentialsRequireConfidential validation in
  CreateClient and admin UpdateClient, consistent with UserUpdateClient
- Normalize client type early in all three paths

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@appleboy appleboy requested a review from Copilot March 21, 2026 12:34
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/templates/user_app_secret.templ Outdated
- Extract shared secret-regeneration card into SecretRegeneratedCard
  in client_shared.templ, parameterized by breadcrumb, labels, and paths
- Refactor AdminClientSecret and UserAppSecret to use the shared component
- Eliminates duplication and prevents long-term drift

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/templates/props.go
Comment thread internal/services/client.go Outdated
… tests

- Update ShowClientCredentials comment from "(admin only)" to
  "(confidential clients)" to reflect current behavior
- Add CreateClient tests for CC flow: confidential success and
  public rejection

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/templates/client_shared.templ Outdated
A new client secret has been successfully generated for "<strong>{ props.ClientName }</strong>"
</div>
<div class="warning-box warning-box-enhanced">
<div class="warning-icon">⚠</div>
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The warning icon is purely decorative but will likely be announced by screen readers as a “warning sign” character. Consider adding aria-hidden="true" to the .warning-icon element (or alternatively role="img" + an explicit aria-label) so the accessible name comes from the nearby “Important Security Notice” text instead of the glyph.

Suggested change
<div class="warning-icon">⚠</div>
<div class="warning-icon" aria-hidden="true">⚠</div>

Copilot uses AI. Check for mistakes.
Comment thread internal/templates/props.go Outdated
IsEdit bool
NameLabel string // Display label: "App Name" (user) or "Client Name" (admin)
ShowClientCredentials bool // Show Client Credentials Flow checkbox (admin only)
ShowClientCredentials bool // Show Client Credentials Flow checkbox (confidential clients)
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The field comment for ShowClientCredentials is a bit misleading: the checkbox is rendered based on this flag, but the confidential-vs-public restriction is enforced separately in the template JS (it’s still shown, just disabled for public). Suggest updating the comment to reflect that this flag controls rendering, not the client-type constraint itself.

Suggested change
ShowClientCredentials bool // Show Client Credentials Flow checkbox (confidential clients)
ShowClientCredentials bool // Control rendering of the Client Credentials Flow checkbox; client-type (confidential vs public) restrictions are enforced in the template JS (e.g. disabling for public clients)

Copilot uses AI. Check for mistakes.
…tials comment

- Add aria-hidden="true" to decorative warning icon in SecretRegeneratedCard
- Clarify ShowClientCredentials comment to reflect rendering vs JS enforcement

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Introduce core.ClientType with IsValid, OrDefault, and NormalizeClientType
- Replace raw string constants with typed ClientType across services and handlers
- Simplify normalize blocks to one-liner OrDefault calls
- Remove redundant enableClientCredentials guard after early-return validation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@appleboy appleboy merged commit dea632f into main Mar 21, 2026
20 of 21 checks passed
@appleboy appleboy deleted the feat/user-app-regenerate-secret branch March 21, 2026 15:03
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.

3 participants