<%= form_with(model: [:admin, application], class: "space-y-6", data: { controller: "application-form form-errors" }) do |form| %> <%= render "shared/form_errors", form: form %>
<%= form.label :name, class: "block text-sm font-medium text-gray-700" %> <%= form.text_field :name, required: true, class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm", placeholder: "My Application" %>
<%= form.label :slug, class: "block text-sm font-medium text-gray-700" %> <%= form.text_field :slug, required: true, 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: "my-app" %>

Lowercase letters, numbers, and hyphens only. Used in URLs and API calls.

<%= form.label :description, class: "block text-sm font-medium text-gray-700" %> <%= form.text_area :description, rows: 3, class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm", placeholder: "Optional description of this application" %>
<%= form.label :icon, "Application Icon", class: "block text-sm font-medium text-gray-700" %> <% if application.icon.attached? %>
<%= image_tag application.icon, class: "h-16 w-16 rounded-lg object-cover border border-gray-200", alt: "Current icon" %>

Current icon

<%= number_to_human_size(application.icon.blob.byte_size) %>

<% end %>

or drag and drop

PNG, JPG, GIF, or SVG up to 2MB

<%= form.label :landing_url, "Landing URL", class: "block text-sm font-medium text-gray-700" %> <%= form.url_field :landing_url, class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm", placeholder: "https://app.example.com" %>

The main URL users will visit to access this application. This will be shown as a link on their dashboard.

<%= form.label :app_type, "Application Type", class: "block text-sm font-medium text-gray-700" %> <%= form.select :app_type, [["OpenID Connect (OIDC)", "oidc"], ["Forward Auth (Reverse Proxy)", "forward_auth"]], {}, { class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm", disabled: application.persisted?, data: { action: "change->application-form#updateFieldVisibility", application_form_target: "appTypeSelect" } } %> <% if application.persisted? %>

Application type cannot be changed after creation.

<% end %>

OIDC Configuration

<%= 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" %>

One URI per line. These are the allowed callback URLs for your application.

<%= form.label :backchannel_logout_uri, "Backchannel Logout URI (Optional)", class: "block text-sm font-medium text-gray-700" %> <%= form.url_field :backchannel_logout_uri, 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://app.example.com/oidc/backchannel-logout" %>

If the application supports OpenID Connect Backchannel Logout, enter the logout endpoint URL. When users log out, Clinch will send logout notifications to this endpoint for immediate session termination. Leave blank if the application doesn't support backchannel logout.

Token Expiration Settings

Configure how long tokens remain valid. Shorter times are more secure but require more frequent refreshes.

<%= form.label :access_token_ttl, "Access Token TTL (seconds)", class: "block text-sm font-medium text-gray-700" %> <%= form.number_field :access_token_ttl, value: application.access_token_ttl || 3600, min: 300, max: 86400, step: 60, class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm" %>

Range: 5 min - 24 hours
Default: 1 hour (3600s)
Current: <%= application.access_token_ttl_human || "1 hour" %>

<%= form.label :refresh_token_ttl, "Refresh Token TTL (seconds)", class: "block text-sm font-medium text-gray-700" %> <%= form.number_field :refresh_token_ttl, value: application.refresh_token_ttl || 2592000, min: 86400, max: 7776000, step: 86400, class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm" %>

Range: 1 day - 90 days
Default: 30 days (2592000s)
Current: <%= application.refresh_token_ttl_human || "30 days" %>

<%= form.label :id_token_ttl, "ID Token TTL (seconds)", class: "block text-sm font-medium text-gray-700" %> <%= form.number_field :id_token_ttl, value: application.id_token_ttl || 3600, min: 300, max: 86400, step: 60, class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm" %>

Range: 5 min - 24 hours
Default: 1 hour (3600s)
Current: <%= application.id_token_ttl_human || "1 hour" %>

Understanding Token Types

Access Token: Used to access protected resources (APIs). Shorter lifetime = more secure. Users won't notice automatic refreshes.

Refresh Token: Used to get new access tokens without re-authentication. Longer lifetime = better UX (less re-logins).

ID Token: Contains user identity information (JWT). Should match access token lifetime in most cases.

💡 Tip: Banking apps use 5-15 min access tokens. Internal tools use 1-4 hours.

Forward Auth Configuration

<%= form.label :domain_pattern, "Domain Pattern", class: "block text-sm font-medium text-gray-700" %> <%= form.text_field :domain_pattern, 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: "*.example.com or app.example.com" %>

Domain pattern to match. Use * for wildcard subdomains (e.g., *.example.com matches app.example.com, api.example.com, etc.)

<%= form.label :headers_config, "Custom Headers Configuration (JSON)", class: "block text-sm font-medium text-gray-700" %> <%= form.text_area :headers_config, value: (application.headers_config.present? && application.headers_config.any? ? JSON.pretty_generate(application.headers_config) : ""), rows: 10, 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: '{"user": "Remote-User", "groups": "Remote-Groups"}', data: { action: "input->json-validator#validate blur->json-validator#format", json_validator_target: "textarea" } %>

Optional: Customize header names sent to your application.

Default headers: X-Remote-User, X-Remote-Email, X-Remote-Name, X-Remote-Groups, X-Remote-Admin

Show available header keys and what data they send

user - User's email address

email - User's email address

name - User's display name (falls back to email if not set)

groups - Comma-separated list of group names (e.g., "admin,developers")

admin - "true" or "false" indicating admin status

Example: {"user": "Remote-User", "groups": "Remote-Groups"}

Need custom user fields? Add them to user's custom_claims for OIDC tokens

<%= form.label :group_ids, "Allowed Groups (Optional)", class: "block text-sm font-medium text-gray-700" %>
<% if @available_groups.any? %> <% @available_groups.each do |group| %>
<%= check_box_tag "application[group_ids][]", group.id, application.allowed_groups.include?(group), class: "h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500" %> <%= label_tag "application_group_ids_#{group.id}", group.name, class: "ml-2 text-sm text-gray-900" %> (<%= pluralize(group.users.count, "member") %>)
<% end %> <% else %>

No groups available. Create groups first to restrict access.

<% end %>

If no groups are selected, all active users can access this application.

<%= form.check_box :active, class: "h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500" %> <%= form.label :active, "Active", class: "ml-2 block text-sm text-gray-900" %>
<%= form.submit application.persisted? ? "Update Application" : "Create Application", class: "rounded-md bg-blue-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-blue-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600" %> <%= link_to "Cancel", admin_applications_path, class: "rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50" %>
<% end %>