{"id":41157702,"url":"https://github.com/gpappsoft/keyrad","last_synced_at":"2026-04-05T09:01:23.259Z","repository":{"id":331961651,"uuid":"1132302798","full_name":"gpappsoft/keyrad","owner":"gpappsoft","description":"A Go-based RADIUS server that authenticates users against Keycloak","archived":false,"fork":false,"pushed_at":"2026-03-30T13:27:01.000Z","size":16318,"stargazers_count":2,"open_issues_count":3,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-30T15:16:12.337Z","etag":null,"topics":["2fa","challenge-response","keycloak","multifactor-authentication","otp","radius","radius-accounting","radius-protocol","radius-server","security","server","standalone","token2","totp"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gpappsoft.png","metadata":{"files":{"readme":"README.MD","changelog":null,"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":null,"dco":null,"cla":null}},"created_at":"2026-01-11T17:54:11.000Z","updated_at":"2026-01-28T15:57:40.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/gpappsoft/keyrad","commit_stats":null,"previous_names":["gpappsoft/keyrad"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/gpappsoft/keyrad","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gpappsoft%2Fkeyrad","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gpappsoft%2Fkeyrad/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gpappsoft%2Fkeyrad/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gpappsoft%2Fkeyrad/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gpappsoft","download_url":"https://codeload.github.com/gpappsoft/keyrad/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gpappsoft%2Fkeyrad/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31430011,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-05T08:13:15.228Z","status":"ssl_error","status_checked_at":"2026-04-05T08:13:11.839Z","response_time":75,"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":["2fa","challenge-response","keycloak","multifactor-authentication","otp","radius","radius-accounting","radius-protocol","radius-server","security","server","standalone","token2","totp"],"created_at":"2026-01-22T19:15:58.791Z","updated_at":"2026-04-05T09:01:23.254Z","avatar_url":"https://github.com/gpappsoft.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# keyrad: Keycloak RADIUS Server\n\nA Go-based RADIUS server that authenticates users against Keycloak, supporting password and OTP (TOTP) flows.\n\nFeatures include:\n- Challenge-response for OTP\n- YAML-based Keycloak and RADIUS config\n- FreeRADIUS-style `clients.conf` for client secrets\n- Optional Message-Authenticator\n- Scope/group-to-RADIUS attribute mapping (with regexp support)\n- **Vendor-Specific Attributes (VSA):** Return vendor-specific attributes (e.g. MikroTik, Cisco, Ubiquiti) in Access-Accept responses based on user roles, groups, or scopes\n- **Configurable OTP mode:** Use standard challenge-response or \u003cpassword\u003e\u003cotp\u003e style\n- **Configurable OTP challenge message** via `otp_challenge_message` in config\n- **Asynchronous/multi-request support:** Multiple RADIUS requests are handled concurrently for high performance\n\n## Requirements\n- Go 1.18+\n- A running Keycloak instance (tested with Keycloak 21+)\n\n## Compilation\n```bash\ngit clone https://github.com/gpappsoft/keyrad.git\ncd keyrad\ngo build -o keyrad main.go\n```\n\n## Configuration\n\n### 1. Keycloak Setup\n- **Create a confidential client** (e.g. `radius-client`) in your realm.\n  - Enable `Service Accounts Enabled`.\n  - Enable `Direct Access Grants`.\n  - Set `Valid Redirect URIs` to `*` (or as needed).\n- **Assign roles to the client service account**:\n  - Go to `Service Account Roles` for your client.\n  - Assign at least:\n    - `view-users`\n    - `query-users`\n    - `view-realm`\n    - `view-authorization`\n- **User setup**:\n  - Users must have credentials set for password or OTP (TOTP) as desired.\n  - To use OTP, users must enroll an OTP device in Keycloak.\n\n### 2. keyrad.yaml\nSee `keyrad.yaml` for a full example.\n\n- To customize the OTP challenge message, add `otp_challenge_message: \"Your custom message\"` to `keyrad.yaml`.\n- The server supports multiple concurrent RADIUS requests (async worker pool, default 8 workers).\n\n### 3. clients.conf\nFreeRADIUS-style client definitions. See `clients.conf` for the format.\n\n### 4. Scope-to-RADIUS Attribute Mapping\n\nMap Keycloak realm roles, groups, or OAuth2 scopes to RADIUS attributes returned in Access-Accept responses. Supports both standard RADIUS attributes and Vendor-Specific Attributes (VSA).\n\nAfter successful authentication, keyrad extracts the user's roles, groups, and scopes from the Keycloak JWT access token and matches them against the `scope_radius_map` keys.\n\n#### Configuration format\n\n```yaml\nscope_radius_map:\n  # Exact match against role/group/scope name\n  admin:\n    - attribute: 6        # Service-Type\n      value: \"6\"          # Administrative-User\n      value_type: integer\n\n  # Multiple attributes per scope\n  vpn:\n    - attribute: 8        # Framed-IP-Address\n      value: \"10.0.0.1\"\n      value_type: ipaddr\n    - vendor: 14988       # MikroTik Vendor ID\n      attribute: 3        # Mikrotik-Group\n      value: \"full\"\n\n  # Vendor-Specific Attributes (VSA)\n  wifi:\n    - vendor: 14988       # MikroTik\n      attribute: 8        # Mikrotik-Rate-Limit\n      value: \"10M/10M\"\n\n  # Regex matching with \"re:\" prefix\n  re:^group_.*:\n    - attribute: 11       # Filter-Id\n      value: \"group-member\"\n```\n\n#### Attribute fields\n\n| Field        | Required | Description                                                        |\n|--------------|----------|--------------------------------------------------------------------|\n| `vendor`     | No       | IANA vendor ID. Omit or set to `0` for standard RADIUS attributes. |\n| `attribute`  | Yes      | Attribute type number.                                             |\n| `value`      | Yes      | Attribute value.                                                   |\n| `value_type` | No       | Encoding type: `string` (default), `integer`, or `ipaddr`.        |\n\n#### Common vendor IDs\n\n| Vendor   | ID    | Reference                                                    |\n|----------|-------|--------------------------------------------------------------|\n| Cisco    | 9     | [Cisco VSA documentation](https://www.cisco.com)             |\n| Microsoft| 311   | RFC 2548                                                     |\n| MikroTik | 14988 | [MikroTik RADIUS dictionary](https://help.mikrotik.com/docs/spaces/ROS/pages/328097/RADIUS) |\n| Ubiquiti | 41112 | Ubiquiti RADIUS dictionary                                   |\n\n#### Keycloak setup for scope/group matching\n\nFor roles and scopes, no extra Keycloak configuration is needed -- they are included in the JWT by default.\n\nFor **group-based matching**, add a \"groups\" protocol mapper to your Keycloak client:\n1. Go to your client's **Client Scopes** \u003e **Dedicated scope** \u003e **Add mapper** \u003e **By configuration** \u003e **Group Membership**.\n2. Set **Token Claim Name** to `groups`.\n3. Disable **Full group path** if you want short group names.\n\n## Usage\n\n### Start the server\n```bash\n./keyrad -c keyrad.yaml -r clients.conf\n```\n- Use `--disable-message-authenticator` to disable Message-Authenticator checks (for legacy clients).\n- Use `--disable-challenge-response` to allow OTP users to authenticate with `\u003cpassword\u003e\u003cotp\u003e` in the User-Password field (no challenge-response).\n- Use `--version` to print version and author.\n\n### Test with radtest\n```bash\nradtest testuser password 127.0.0.1 0 test\n```\n- For OTP (default): Enter password first, then respond to challenge with OTP code (customizable message).\n- For OTP with `--disable-challenge-response`: Enter `\u003cpassword\u003e\u003cotp\u003e` as the password (e.g. `mypassword123456`).\n\n## Advanced Features\n- **Challenge-response**: Standard RADIUS Access-Challenge for OTP, or disable for legacy OTP style.\n- **Configurable OTP challenge message**: Set `otp_challenge_message` in your config for custom challenge text.\n- **Scope/group mapping**: Map Keycloak realm roles, groups, or OAuth2 scopes to RADIUS attributes. Supports regexp keys (e.g. `re:^group_.*`).\n- **Vendor-Specific Attributes (VSA)**: Return vendor-specific attributes in Access-Accept based on user roles/groups. Supports any vendor by IANA vendor ID (e.g. MikroTik 14988, Cisco 9, Microsoft 311).\n- **TLS verification**: Set `insecure_skip_tls_verify: true` for self-signed Keycloak certs.\n- **Asynchronous/multi-request support**: Multiple RADIUS requests are handled concurrently for high performance.\n\n## Troubleshooting\n- **403 errors**: Ensure your Keycloak client has the correct service account roles.\n- **Invalid Message-Authenticator**: Check shared secrets in `clients.conf` and your RADIUS client.\n- **OTP not working**: Ensure user has the credential enrolled in Keycloak.\n- **Legacy OTP**: If your client cannot handle RADIUS challenge-response, use `--disable-challenge-response`.\n\n## Support\nIf you need professional support, please write to\n\n[info@sec73.io](mailto:info@sec73.io)\n\n## Disclaimer\nThis project is provided as-is, without warranty of any kind. Use at your own risk. The maintainers are not responsible for any damage, data loss, or security issues resulting from the use or misuse of this software. Always review and test in a safe environment before deploying to production.\n\n## License\nApache-2.0\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgpappsoft%2Fkeyrad","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgpappsoft%2Fkeyrad","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgpappsoft%2Fkeyrad/lists"}