PKCE is now default enabled. You can now create public / no-secret apps OIDC apps
This commit is contained in:
@@ -120,6 +120,51 @@
|
||||
<div id="oidc-fields" class="space-y-6 border-t border-gray-200 pt-6 <%= 'hidden' unless application.oidc? || !application.persisted? %>" data-application-form-target="oidcFields">
|
||||
<h3 class="text-base font-semibold text-gray-900">OIDC Configuration</h3>
|
||||
|
||||
<!-- Client Type Selection (only for new applications) -->
|
||||
<% unless application.persisted? %>
|
||||
<div class="border border-gray-200 rounded-lg p-4 bg-gray-50">
|
||||
<h4 class="text-sm font-semibold text-gray-900 mb-3">Client Type</h4>
|
||||
<div class="space-y-3">
|
||||
<div class="flex items-start">
|
||||
<%= form.radio_button :is_public_client, "false", checked: !application.is_public_client, class: "mt-1 h-4 w-4 border-gray-300 text-blue-600 focus:ring-blue-500", data: { action: "change->application-form#updatePkceVisibility" } %>
|
||||
<div class="ml-3">
|
||||
<label for="application_is_public_client_false" class="block text-sm font-medium text-gray-900">Confidential Client (Recommended)</label>
|
||||
<p class="text-sm text-gray-500">Backend server app that can securely store a client secret. Examples: traditional web apps, server-to-server APIs.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-start">
|
||||
<%= form.radio_button :is_public_client, "true", checked: application.is_public_client, class: "mt-1 h-4 w-4 border-gray-300 text-blue-600 focus:ring-blue-500", data: { action: "change->application-form#updatePkceVisibility" } %>
|
||||
<div class="ml-3">
|
||||
<label for="application_is_public_client_true" class="block text-sm font-medium text-gray-900">Public Client</label>
|
||||
<p class="text-sm text-gray-500">Frontend-only app that cannot store secrets securely. Examples: SPAs (React/Vue), mobile apps, CLI tools. <strong class="text-amber-600">PKCE is required.</strong></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% else %>
|
||||
<!-- Show client type for existing applications (read-only) -->
|
||||
<div class="flex items-center gap-2 text-sm">
|
||||
<span class="font-medium text-gray-700">Client Type:</span>
|
||||
<% if application.public_client? %>
|
||||
<span class="inline-flex items-center rounded-md bg-amber-50 px-2 py-1 text-xs font-medium text-amber-700 ring-1 ring-inset ring-amber-600/20">Public Client (PKCE Required)</span>
|
||||
<% else %>
|
||||
<span class="inline-flex items-center rounded-md bg-green-50 px-2 py-1 text-xs font-medium text-green-700 ring-1 ring-inset ring-green-600/20">Confidential Client</span>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<!-- PKCE Requirement (only for confidential clients) -->
|
||||
<div id="pkce-options" data-application-form-target="pkceOptions" class="<%= 'hidden' if application.persisted? && application.public_client? %>">
|
||||
<div class="flex items-center">
|
||||
<%= form.check_box :require_pkce, class: "h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500" %>
|
||||
<%= form.label :require_pkce, "Require PKCE (Proof Key for Code Exchange)", class: "ml-2 block text-sm font-medium text-gray-900" %>
|
||||
</div>
|
||||
<p class="ml-6 text-sm text-gray-500">
|
||||
Recommended for enhanced security (OAuth 2.1 best practice).
|
||||
<br><span class="text-xs text-gray-400">Note: Public clients always require PKCE regardless of this setting.</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<%= form.label :redirect_uris, "Redirect URIs", class: "block text-sm font-medium text-gray-700" %>
|
||||
<%= form.text_area :redirect_uris, rows: 4, class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm font-mono", placeholder: "https://example.com/callback\nhttps://app.example.com/auth/callback" %>
|
||||
|
||||
@@ -1,17 +1,30 @@
|
||||
<div class="mb-6">
|
||||
<% if flash[:client_id] && flash[:client_secret] %>
|
||||
<% if flash[:client_id] %>
|
||||
<div class="bg-yellow-50 border border-yellow-200 rounded-md p-4 mb-6">
|
||||
<h4 class="text-sm font-medium text-yellow-800 mb-2">🔐 OIDC Client Credentials</h4>
|
||||
<p class="text-xs text-yellow-700 mb-3">Copy these credentials now. The client secret will not be shown again.</p>
|
||||
<% if flash[:public_client] %>
|
||||
<p class="text-xs text-yellow-700 mb-3">This is a public client. Copy the client ID below.</p>
|
||||
<% else %>
|
||||
<p class="text-xs text-yellow-700 mb-3">Copy these credentials now. The client secret will not be shown again.</p>
|
||||
<% end %>
|
||||
<div class="space-y-2">
|
||||
<div>
|
||||
<span class="text-xs font-medium text-yellow-700">Client ID:</span>
|
||||
</div>
|
||||
<code class="block bg-yellow-100 px-3 py-2 rounded font-mono text-xs break-all"><%= flash[:client_id] %></code>
|
||||
<div class="mt-3">
|
||||
<span class="text-xs font-medium text-yellow-700">Client Secret:</span>
|
||||
</div>
|
||||
<code class="block bg-yellow-100 px-3 py-2 rounded font-mono text-xs break-all"><%= flash[:client_secret] %></code>
|
||||
<% if flash[:client_secret] %>
|
||||
<div class="mt-3">
|
||||
<span class="text-xs font-medium text-yellow-700">Client Secret:</span>
|
||||
</div>
|
||||
<code class="block bg-yellow-100 px-3 py-2 rounded font-mono text-xs break-all"><%= flash[:client_secret] %></code>
|
||||
<% elsif flash[:public_client] %>
|
||||
<div class="mt-3">
|
||||
<span class="text-xs font-medium text-yellow-700">Client Secret:</span>
|
||||
</div>
|
||||
<div class="bg-yellow-100 px-3 py-2 rounded text-xs text-yellow-600">
|
||||
Public clients do not have a client secret. PKCE is required.
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
@@ -93,24 +106,57 @@
|
||||
<%= button_to "Regenerate Credentials", regenerate_credentials_admin_application_path(@application), method: :post, data: { turbo_confirm: "This will invalidate the current credentials. Continue?" }, class: "text-sm text-red-600 hover:text-red-900" %>
|
||||
</div>
|
||||
<dl class="space-y-4">
|
||||
<% unless flash[:client_id] && flash[:client_secret] %>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-gray-500">Client Type</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900">
|
||||
<% if @application.public_client? %>
|
||||
<span class="inline-flex items-center rounded-full bg-blue-100 px-2 py-1 text-xs font-medium text-blue-700">Public</span>
|
||||
<% else %>
|
||||
<span class="inline-flex items-center rounded-full bg-gray-100 px-2 py-1 text-xs font-medium text-gray-700">Confidential</span>
|
||||
<% end %>
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-gray-500">PKCE</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900">
|
||||
<% if @application.requires_pkce? %>
|
||||
<span class="inline-flex items-center rounded-full bg-green-100 px-2 py-1 text-xs font-medium text-green-700">Required</span>
|
||||
<% else %>
|
||||
<span class="inline-flex items-center rounded-full bg-gray-100 px-2 py-1 text-xs font-medium text-gray-700">Optional</span>
|
||||
<% end %>
|
||||
</dd>
|
||||
</div>
|
||||
</div>
|
||||
<% unless flash[:client_id] %>
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-gray-500">Client ID</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900">
|
||||
<code class="block bg-gray-100 px-3 py-2 rounded font-mono text-xs break-all"><%= @application.client_id %></code>
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-gray-500">Client Secret</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900">
|
||||
<div class="bg-gray-100 px-3 py-2 rounded text-xs text-gray-500 italic">
|
||||
🔒 Client secret is stored securely and cannot be displayed
|
||||
</div>
|
||||
<p class="mt-2 text-xs text-gray-500">
|
||||
To get a new client secret, use the "Regenerate Credentials" button above.
|
||||
</p>
|
||||
</dd>
|
||||
</div>
|
||||
<% if @application.confidential_client? %>
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-gray-500">Client Secret</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900">
|
||||
<div class="bg-gray-100 px-3 py-2 rounded text-xs text-gray-500 italic">
|
||||
🔒 Client secret is stored securely and cannot be displayed
|
||||
</div>
|
||||
<p class="mt-2 text-xs text-gray-500">
|
||||
To get a new client secret, use the "Regenerate Credentials" button above.
|
||||
</p>
|
||||
</dd>
|
||||
</div>
|
||||
<% else %>
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-gray-500">Client Secret</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900">
|
||||
<div class="bg-blue-50 px-3 py-2 rounded text-xs text-blue-600">
|
||||
Public clients do not use a client secret. PKCE is required for authorization.
|
||||
</div>
|
||||
</dd>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-gray-500">Redirect URIs</dt>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<%# Enhanced Flash Messages with Support for Multiple Types and Auto-Dismiss %>
|
||||
<% flash.each do |type, message| %>
|
||||
<% next if message.blank? %>
|
||||
<%# Skip credential-related flash messages - they're displayed in a special credentials box %>
|
||||
<% next if %w[client_id client_secret public_client].include?(type.to_s) %>
|
||||
|
||||
<%
|
||||
# Map flash types to styling
|
||||
|
||||
Reference in New Issue
Block a user