Security-review follow-ups on the OIDC flows. IPv6 loopback redirect_uri in dynamic client registration (RFC 8252): - valid_redirect_uri? compared URI#host, which returns the bracketed "[::1]" for IPv6 literals, so http://[::1]:PORT/... was always rejected. Compare #hostname (unbracketed) instead, unblocking IPv6-only native clients. Extract redirect_authorize_error (removes 12 copies of the boilerplate): - The authorize/consent flows built the error redirect by hand ~a dozen times (error_uri = "...?error=..."; += "&error_description=#{CGI.escape ...}"; += state; redirect_to). One helper now composes the query, and — unlike every copy — appends "&error=..." when the redirect_uri already has a query string instead of a malformed second "?". Extract token-endpoint helpers (removes ~80 duplicated lines): - authenticate_token_client: the identical client-auth preamble shared by the authorization-code, refresh, and device-code grants. - render_token_triple: the access + refresh + id_token mint and RFC 6749 §5.1 response shared by the authorization-code and device-code grants. Single source of truth for scope descriptions: - New OidcHelper#scope_description + shared shared/_scope_list partial, used by both the browser consent screen and the device authorization screen; drops the scope_labels hash and the hard-coded per-scope blocks that would have drifted. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Q4ATZHoMCWqvSpE2yYoie
48 lines
2.6 KiB
ERB
48 lines
2.6 KiB
ERB
<div class="mx-auto max-w-md">
|
|
<div class="bg-white dark:bg-gray-800 py-8 px-6 shadow rounded-lg sm:px-10">
|
|
<div class="mb-8 text-center">
|
|
<% if @application.icon.attached? %>
|
|
<div class="mx-auto h-20 w-20 mb-4">
|
|
<%= app_icon_picture @application, class: "mx-auto h-20 w-20 rounded-xl object-cover border-2 border-gray-200 dark:border-gray-700 shadow-sm" %>
|
|
</div>
|
|
<% else %>
|
|
<div class="mx-auto mb-4">
|
|
<%= render "shared/app_monogram", name: @application.name, class: "h-20 w-20 rounded-xl shadow-sm" %>
|
|
</div>
|
|
<% end %>
|
|
<h2 class="text-2xl font-bold text-gray-900 dark:text-gray-100">Authorize Application</h2>
|
|
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">
|
|
<strong><%= @application.name %></strong> is requesting access to your account.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="mb-6">
|
|
<h3 class="text-sm font-medium text-gray-900 dark:text-gray-100 mb-3">This application will be able to:</h3>
|
|
<%= render "shared/scope_list", scopes: @scopes %>
|
|
</div>
|
|
|
|
<div class="rounded-md bg-blue-50 dark:bg-blue-900/30 p-4 mb-6">
|
|
<div class="flex">
|
|
<svg class="h-5 w-5 text-blue-400 mr-3 flex-shrink-0" viewBox="0 0 20 20" fill="currentColor">
|
|
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"/>
|
|
</svg>
|
|
<div class="text-sm text-blue-700 dark:text-blue-300">
|
|
<p>You'll be redirected to:</p>
|
|
<p class="mt-1 font-mono text-xs break-all"><%= @redirect_uri %></p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<%= form_with url: "/oauth/authorize/consent", method: :post, class: "space-y-3", data: { turbo: false }, local: true do |form| %>
|
|
<%= form.submit "Authorize",
|
|
class: "w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 dark:focus:ring-offset-gray-900 focus:ring-blue-500" %>
|
|
|
|
<%= button_tag "Deny",
|
|
type: :submit,
|
|
name: :deny,
|
|
value: "1",
|
|
class: "w-full flex justify-center py-2 px-4 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm text-sm font-medium text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-700 dark:ring-gray-600 hover:bg-gray-50 dark:hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-offset-2 dark:focus:ring-offset-gray-900 focus:ring-blue-500" %>
|
|
<% end %>
|
|
</div>
|
|
</div>
|