{"id":47938125,"url":"https://github.com/thadeu/clowk-ruby","last_synced_at":"2026-04-04T07:54:37.443Z","repository":{"id":346246640,"uuid":"1188909294","full_name":"thadeu/clowk-ruby","owner":"thadeu","description":"Clowk is an **authentication broker**, not an authentication UI provider.","archived":false,"fork":false,"pushed_at":"2026-03-23T21:08:34.000Z","size":78,"stargazers_count":0,"open_issues_count":3,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-04T07:54:36.210Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thadeu.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-03-22T18:41:12.000Z","updated_at":"2026-03-23T19:15:26.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/thadeu/clowk-ruby","commit_stats":null,"previous_names":["thadeu/clowk-ruby"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/thadeu/clowk-ruby","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thadeu%2Fclowk-ruby","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thadeu%2Fclowk-ruby/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thadeu%2Fclowk-ruby/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thadeu%2Fclowk-ruby/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thadeu","download_url":"https://codeload.github.com/thadeu/clowk-ruby/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thadeu%2Fclowk-ruby/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31392188,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T04:26:24.776Z","status":"ssl_error","status_checked_at":"2026-04-04T04:23:34.147Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-04T07:54:36.887Z","updated_at":"2026-04-04T07:54:37.430Z","avatar_url":"https://github.com/thadeu.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Clowk Ruby SDK\n\nClowk is the Ruby gem for integrating Clowk authentication into Rails applications.\n\nIt focuses on a small client-side surface:\n\n- redirect users to Clowk\n- verify the JWT returned by Clowk\n- expose Rails-friendly auth helpers\n- provide a minimal HTTP client for the Clowk API\n\n## Product domains\n\nClowk uses different domains for different concerns:\n\n- `clowk.in`: public product site\n- `app.clowk.in`: dashboard used to manage apps and instances\n- `*.clowk.dev`: per-instance auth domain used by your end users\n\nFor a Rails app using this gem, the important part is the instance auth domain. Your app redirects users there, Clowk authenticates them, then redirects back with a signed JWT.\n\n## Install\n\n```ruby\n# Gemfile\ngem 'clowk'\n```\n\n## Quick start\n\n```ruby\n# config/initializers/clowk.rb\nClowk.configure do |config|\n  config.publishable_key = ENV['CLOWK_PUBLISHABLE_KEY']\n  config.secret_key = ENV['CLOWK_SECRET_KEY']\nend\n```\n\n```ruby\n# config/routes.rb\nRails.application.routes.draw do\n  mount Clowk::Engine =\u003e '/clowk'\nend\n```\n\n```ruby\nclass ApplicationController \u003c ActionController::Base\n  include Clowk::Authenticable\nend\n```\n\n```ruby\nclass DashboardController \u003c ApplicationController\n  before_action :authenticate_clowk!\n\n  def index\n    @user = current_clowk\n  end\nend\n```\n\n## Authentication flow\n\n1. Your app redirects the user to `*.clowk.dev`.\n2. Clowk authenticates the user.\n3. Clowk redirects back to your callback URL with `token` and `state`.\n4. The gem validates `state`, verifies the JWT, stores the authenticated session, and redirects back to a safe internal path.\n\nThe callback flow includes:\n\n- session-backed `state` validation\n- JWT verification with your instance `secret_key`\n- internal-only redirect sanitization\n- session reset before persisting the authenticated user\n- `httponly` cookie persistence with `SameSite=Lax`\n\n## Configuration\n\n```ruby\nClowk.configure do |config|\n  config.secret_key = ENV['CLOWK_SECRET_KEY']\n  config.publishable_key = ENV['CLOWK_PUBLISHABLE_KEY']\n  config.subdomain_url = 'https://acme.clowk.dev'\n  config.prefix_by = :clowk\n\n  config.after_sign_in_path = '/'\n  config.after_sign_out_path = '/'\n\n  config.api_base_url = 'https://api.clowk.dev/client/v1'\n  config.callback_path = '/clowk/oauth/callback'\n  config.mount_path = '/clowk'\n\n  config.http_open_timeout = 5\n  config.http_read_timeout = 10\n  config.http_write_timeout = 10\n  config.http_retry_attempts = 2\n  config.http_retry_interval = 0.05\n  config.http_logger = Rails.logger\nend\n```\n\nImportant settings:\n\n| Setting | Purpose |\n| --- | --- |\n| `secret_key` | Required. Used to verify JWT signatures. |\n| `publishable_key` | Preferred for auth URL resolution. The gem resolves the latest instance URL from it before sign in/sign up. |\n| `subdomain_url` | Fallback auth domain when you do not want publishable-key-based resolution. |\n| `prefix_by` | Prefix used to generate helper names. Default: `:clowk`. |\n| `mount_path` | Local mount prefix used by helper path generation. Default: `/clowk`. |\n| `callback_path` | Callback route Clowk redirects back to. Default: `/clowk/oauth/callback`. |\n| `http_logger` | Optional logger used by `Clowk::Http`. |\n\nAuth URL resolution priority:\n\n1. `publishable_key`\n2. `subdomain_url`\n\nWhen `publishable_key` is present, the gem resolves the current auth base URL first and caches it briefly in memory. The lookup endpoint returns the full instance JSON payload, and the gem derives the final auth URL from that data (including `subdomain`). This keeps dashboard subdomain changes visible without redeploying the client app. If you do not want that lookup, configure only `subdomain_url`.\n\nInternally, that lookup is done through `Clowk::SDK::Client`, via `client.subdomains.find_by_pk('pk_...')`.\n\nIf you mount the engine under a different prefix, keep `mount_path` and `callback_path` aligned with that choice.\n\nExample:\n\n```ruby\nClowk.configure do |config|\n  config.mount_path = '/auth'\n  config.callback_path = '/auth/oauth/callback'\nend\n\nRails.application.routes.draw do\n  mount Clowk::Engine =\u003e '/auth'\nend\n```\n\n## Generated helpers\n\nWith the default `prefix_by = :clowk`, the concern exposes:\n\n- `current_clowk`\n- `authenticate_clowk!`\n- `clowk_signed_in?`\n\nYou can change the prefix to avoid collisions with another auth system.\n\n```ruby\nClowk.configure do |config|\n  config.prefix_by = :member\nend\n```\n\nThat generates:\n\n- `current_member`\n- `authenticate_member!`\n- `member_signed_in?`\n\n## Current subject\n\n`current_clowk` returns a `Clowk::Current` object.\n\n```ruby\ncurrent_clowk.id\ncurrent_clowk.email\ncurrent_clowk.name\ncurrent_clowk.avatar_url\ncurrent_clowk.provider\ncurrent_clowk.instance_id\ncurrent_clowk.app_id\n```\n\nYou can also access raw claims:\n\n```ruby\ncurrent_clowk[:sub]\ncurrent_clowk.to_h\n```\n\n## Route protection\n\n```ruby\nclass AdminController \u003c ApplicationController\n  before_action :authenticate_clowk!\nend\n```\n\nUse `authenticate_clowk!` for protected pages. Use `current_clowk` when the route can be public but should still know who is authenticated.\n\n## View and URL helpers\n\nLocal mounted routes:\n\n```erb\n\u003c%= link_to 'Sign in', clowk_sign_in_path(return_to: dashboard_path) %\u003e\n\u003c%= link_to 'Sign up', clowk_sign_up_path(return_to: dashboard_path) %\u003e\n\u003c%= link_to 'Sign out', clowk_sign_out_path %\u003e\n```\n\nDirect remote URLs:\n\n```erb\n\u003c%= link_to 'Direct sign in', clowk_sign_in_url(redirect_to: dashboard_url) %\u003e\n\u003c%= link_to 'Direct sign up', clowk_sign_up_url(redirect_to: dashboard_url) %\u003e\n```\n\nWhen `publishable_key` is configured, these helpers resolve the latest instance URL before building the final `sign-in` or `sign-up` destination. When it is absent, they use `subdomain_url` directly.\n\nMounted routes exposed by the engine:\n\n- `/clowk/sign_in`\n- `/clowk/sign_up`\n- `/clowk/sign_out`\n- `/clowk/oauth/callback`\n\nWhen you mount the engine elsewhere, the same route set is exposed under your chosen prefix.\n\n## Token sources\n\nThe concern can read the token from:\n\n- `params[:token]`\n- cookies\n- `Authorization: Bearer \u003ctoken\u003e`\n\nThat keeps the integration usable for callback routes, regular controllers, and API-style endpoints.\n\n## SDK Client\n\nThe gem includes a resource-oriented SDK for the Clowk API.\n\n```ruby\nclient = Clowk::SDK::Client.new\n```\n\nThe client uses your global configuration by default. You can also pass options explicitly:\n\n```ruby\nclient = Clowk::SDK::Client.new(\n  secret_key: 'sk_live_xxx',\n  publishable_key: 'pk_live_xxx'\n)\n```\n\n### Resources\n\nEach resource is accessible as a method on the client:\n\n```ruby\nclient.users\nclient.sessions\nclient.subdomains\n```\n\nThese return `Clowk::SDK::Resource` subclasses with a standard CRUD interface:\n\n```ruby\nclient.users.list\nclient.users.find('user_123')\nclient.users.show('user_123')\nclient.users.destroy('user_123')\n```\n\n### Token verification\n\n```ruby\nresponse = client.tokens.verify(token: params[:token])\n\nresponse.status       # =\u003e 200\nresponse.success?     # =\u003e true\nresponse.body_parsed  # =\u003e { 'valid' =\u003e true }\n```\n\n### Subdomain resolution\n\n```ruby\nresponse = client.subdomains.find_by_pk('pk_live_xxx')\n```\n\n### Search operators\n\nThe `search` method uses a Zendesk-style query syntax. You can use keyword arguments or a raw string for advanced operators.\n\n**Keywords:**\n\n```ruby\nclient.users.search(email: \"user@example.com\")\n# GET /users/search?query=email%3Auser%40example.com\n\nclient.users.search(status: \"active\", role: \"admin\")\n# GET /users/search?query=status%3Aactive+role%3Aadmin\n```\n\n**Raw string** for custom operators like `\u003e`, `\u003c`, `\u003e=`:\n\n```ruby\nclient.users.search(\"email:user@example.com active:true created_at\u003e2026-01-01\")\n# GET /users/search?query=email%3Auser%40example.com+active%3Atrue+created_at%3E2026-01-01\n```\n\nThe raw string is sent as-is, giving full control over the query syntax. The API backend parses and applies the operators.\n\n### Raw HTTP methods\n\nThe client also exposes raw HTTP methods for custom requests:\n\n```ruby\nclient.get('custom/endpoint')\nclient.post('custom/endpoint', { key: 'value' })\nclient.put('custom/endpoint', { key: 'value' })\nclient.patch('custom/endpoint', { key: 'value' })\nclient.delete('custom/endpoint')\nclient.head('custom/endpoint')\nclient.options('custom/endpoint')\n```\n\n## `Clowk::Http::Response`\n\nHTTP responses are returned as `Clowk::Http::Response` objects.\n\n```ruby\nresponse = client.get('users/user_123')\n\nresponse.status       # =\u003e 200\nresponse.success?     # =\u003e true\nresponse.body         # =\u003e '{\"id\":\"user_123\"}'\nresponse.body_parsed  # =\u003e { 'id' =\u003e 'user_123' }\nresponse.headers      # =\u003e { 'content-type' =\u003e ['application/json'] }\n```\n\nFor compatibility, the response also supports:\n\n```ruby\nresponse[:status]\nresponse[:success?]\nresponse.to_h\n```\n\n## HTTP middleware\n\n`Clowk::Http` uses a small internal middleware stack built on `Net::HTTP`.\n\nIncluded behavior:\n\n- request and response logging\n- open, read, and write timeouts\n- retry on retryable network errors\n- automatic JSON request encoding\n- automatic `body_parsed` JSON decoding when possible\n\n## Scope\n\nThis gem is intentionally narrow. It does not try to replace your entire app session architecture or act as an auth server.\n\nIts job is to make the Rails side of Clowk integration predictable:\n\n- start authentication\n- validate callbacks safely\n- expose a clean authenticated subject\n- make future Clowk API access straightforward\n\n## License\n\nMIT. See `LICENSE`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthadeu%2Fclowk-ruby","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthadeu%2Fclowk-ruby","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthadeu%2Fclowk-ruby/lists"}