{"id":13878048,"url":"https://github.com/xlgmokha/saml-kit","last_synced_at":"2026-01-12T14:12:49.341Z","repository":{"id":39861263,"uuid":"115151471","full_name":"xlgmokha/saml-kit","owner":"xlgmokha","description":"SAML 2.0 SDK for Ruby.","archived":false,"fork":false,"pushed_at":"2025-12-03T21:01:57.000Z","size":1324,"stargazers_count":8,"open_issues_count":5,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-03T12:57:07.899Z","etag":null,"topics":["ruby","saml","saml-assertion","saml-idp","saml-metadata","saml2"],"latest_commit_sha":null,"homepage":"https://rubygems.org/gems/saml-kit","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xlgmokha.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2017-12-22T21:30:38.000Z","updated_at":"2025-12-03T17:44:24.000Z","dependencies_parsed_at":"2023-07-15T14:21:14.882Z","dependency_job_id":null,"html_url":"https://github.com/xlgmokha/saml-kit","commit_stats":null,"previous_names":["saml-kit/saml-kit"],"tags_count":62,"template":false,"template_full_name":null,"purl":"pkg:github/xlgmokha/saml-kit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xlgmokha%2Fsaml-kit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xlgmokha%2Fsaml-kit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xlgmokha%2Fsaml-kit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xlgmokha%2Fsaml-kit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xlgmokha","download_url":"https://codeload.github.com/xlgmokha/saml-kit/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xlgmokha%2Fsaml-kit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28340384,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T12:22:26.515Z","status":"ssl_error","status_checked_at":"2026-01-12T12:22:10.856Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: 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":["ruby","saml","saml-assertion","saml-idp","saml-metadata","saml2"],"created_at":"2024-08-06T08:01:38.386Z","updated_at":"2026-01-12T14:12:49.314Z","avatar_url":"https://github.com/xlgmokha.png","language":"Ruby","funding_links":[],"categories":["Ruby"],"sub_categories":[],"readme":"Saml::Kit is a library with the purpose of creating and consuming SAML\ndocuments. It supports the HTTP Post and HTTP Redirect bindings. It can\ncreate Service Provider Metadata, Identity Provider Metadata,\nAuthnRequest, Response, LogoutRequest, LogoutResponse documents.\nIt also supports generating signed and encrypted assertions.\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'saml-kit'\n```\n\nAnd then execute:\n\n    $ bundle\n\nOr install it yourself as:\n\n    $ gem install saml-kit\n\n## Usage\n\nTo specify a global configuration: (useful for a rails application)\n\n```ruby\nSaml::Kit.configure do |configuration|\n  configuration.entity_id = ENV['ISSUER']\n  configuration.generate_key_pair_for(use: :signing)\n  configuration.add_key_pair(ENV[\"CERTIFICATE\"], ENV[\"PRIVATE_KEY\"], passphrase: ENV['PASSPHRASE'], use: :signing)\n  configuration.generate_key_pair_for(use: :encryption)\nend\n```\n\n### Metadata\n\nTo generate metadata for an Identity Provider.\n\n```ruby\nSaml::Kit::Metadata.build_xml do |builder|\n  builder.contact_email = 'hi@example.com'\n  builder.organization_name = \"Acme, Inc\"\n  builder.organization_url = 'https://www.example.com'\n  builder.build_identity_provider do |x|\n    x.add_single_sign_on_service('https://www.example.com/login', binding: :http_post)\n    x.add_single_sign_on_service('https://www.example.com/login', binding: :http_redirect)\n    x.add_single_logout_service('https://www.example.com/logout', binding: :http_post)\n    x.name_id_formats = [ Saml::Kit::Namespaces::EMAIL_ADDRESS ]\n    x.attributes \u003c\u003c :id\n    x.attributes \u003c\u003c :email\n  end\nend\n```\n\nWill produce something like:\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003cEntityDescriptor xmlns=\"urn:oasis:names:tc:SAML:2.0:metadata\" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\" ID=\"_efe0c000-8d0d-4406-96b8-61f649e004f6\" entityID=\"\"\u003e\n  \u003cIDPSSODescriptor WantAuthnRequestsSigned=\"true\" protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\"\u003e\n    \u003cSingleLogoutService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\" Location=\"https://www.example.com/logout\"/\u003e\n    \u003cNameIDFormat\u003eurn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress\u003c/NameIDFormat\u003e\n    \u003cSingleSignOnService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\" Location=\"https://www.example.com/login\"/\u003e\n    \u003cSingleSignOnService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect\" Location=\"https://www.example.com/login\"/\u003e\n    \u003csaml:Attribute Name=\"id\"/\u003e\n    \u003csaml:Attribute Name=\"email\"/\u003e\n  \u003c/IDPSSODescriptor\u003e\n  \u003cOrganization\u003e\n    \u003cOrganizationName xml:lang=\"en\"\u003eAcme, Inc\u003c/OrganizationName\u003e\n    \u003cOrganizationDisplayName xml:lang=\"en\"\u003eAcme, Inc\u003c/OrganizationDisplayName\u003e\n    \u003cOrganizationURL xml:lang=\"en\"\u003ehttps://www.example.com\u003c/OrganizationURL\u003e\n  \u003c/Organization\u003e\n  \u003cContactPerson contactType=\"technical\"\u003e\n    \u003cCompany\u003emailto:hi@example.com\u003c/Company\u003e\n  \u003c/ContactPerson\u003e\n\u003c/EntityDescriptor\u003e\n```\n\nTo generate service provider metadata:\n\n```xml\nmetadata = Saml::Kit::Metadata.build do |builder|\n  builder.contact_email = 'hi@example.com'\n  builder.organization_name = \"Acme, Inc\"\n  builder.organization_url = 'https://www.example.com'\n  builder.build_service_provider do |x|\n    x.add_assertion_consumer_service('https://www.example.com/consume', binding: :http_post)\n    x.add_single_logout_service('https://www.example.com/logout', binding: :http_post)\n  end\nend\nputs metadata.to_xml(pretty: true)\n```\n\nWill produce something like:\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003cEntityDescriptor xmlns=\"urn:oasis:names:tc:SAML:2.0:metadata\" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\" ID=\"_3ff5e4b3-4fce-4cc9-b278-6cb3a0a8cb10\" entityID=\"\"\u003e\n  \u003cSPSSODescriptor AuthnRequestsSigned=\"false\" WantAssertionsSigned=\"true\" protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\"\u003e\n    \u003cSingleLogoutService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\" Location=\"https://www.example.com/logout\"/\u003e\n    \u003cNameIDFormat\u003eurn:oasis:names:tc:SAML:2.0:nameid-format:persistent\u003c/NameIDFormat\u003e\n    \u003cAssertionConsumerService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\" Location=\"https://www.example.com/consume\" index=\"0\" isDefault=\"true\"/\u003e\n  \u003c/SPSSODescriptor\u003e\n  \u003cOrganization\u003e\n    \u003cOrganizationName xml:lang=\"en\"\u003eAcme, Inc\u003c/OrganizationName\u003e\n    \u003cOrganizationDisplayName xml:lang=\"en\"\u003eAcme, Inc\u003c/OrganizationDisplayName\u003e\n    \u003cOrganizationURL xml:lang=\"en\"\u003ehttps://www.example.com\u003c/OrganizationURL\u003e\n  \u003c/Organization\u003e\n  \u003cContactPerson contactType=\"technical\"\u003e\n    \u003cCompany\u003emailto:hi@example.com\u003c/Company\u003e\n  \u003c/ContactPerson\u003e\n\u003c/EntityDescriptor\u003e\n```\n\nTo produce Metadata with an IDPSSODescriptor and SPSSODescriptor.\n\n```ruby\nmetadata = Saml::Kit::Metadata.build do |builder|\n  builder.contact_email = 'hi@example.com'\n  builder.organization_name = \"Acme, Inc\"\n  builder.organization_url = 'https://www.example.com'\n  builder.build_identity_provider do |x|\n    x.add_single_sign_on_service('https://www.example.com/login', binding: :http_post)\n    x.add_single_sign_on_service('https://www.example.com/login', binding: :http_redirect)\n    x.add_single_logout_service('https://www.example.com/logout', binding: :http_post)\n    x.name_id_formats = [ Saml::Kit::Namespaces::EMAIL_ADDRESS ]\n    x.attributes \u003c\u003c :id\n    x.attributes \u003c\u003c :email\n  end\n  builder.build_service_provider do |x|\n    x.add_assertion_consumer_service('https://www.example.com/consume', binding: :http_post)\n    x.add_single_logout_service('https://www.example.com/logout', binding: :http_post)\n  end\nend\nputs metadata.to_xml(pretty: true)\n```\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003cEntityDescriptor xmlns=\"urn:oasis:names:tc:SAML:2.0:metadata\" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\" ID=\"_a29a3a9d-ad16-4839-8f5d-a59daed6f3ce\" entityID=\"\"\u003e\n  \u003cIDPSSODescriptor WantAuthnRequestsSigned=\"true\" protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\"\u003e\n    \u003cSingleLogoutService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\" Location=\"https://www.example.com/logout\"/\u003e\n    \u003cNameIDFormat\u003eurn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress\u003c/NameIDFormat\u003e\n    \u003cSingleSignOnService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\" Location=\"https://www.example.com/login\"/\u003e\n    \u003cSingleSignOnService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect\" Location=\"https://www.example.com/login\"/\u003e\n    \u003csaml:Attribute Name=\"id\"/\u003e\n    \u003csaml:Attribute Name=\"email\"/\u003e\n  \u003c/IDPSSODescriptor\u003e\n  \u003cSPSSODescriptor AuthnRequestsSigned=\"false\" WantAssertionsSigned=\"true\" protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\"\u003e\n    \u003cSingleLogoutService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\" Location=\"https://www.example.com/logout\"/\u003e\n    \u003cNameIDFormat\u003eurn:oasis:names:tc:SAML:2.0:nameid-format:persistent\u003c/NameIDFormat\u003e\n    \u003cAssertionConsumerService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\" Location=\"https://www.example.com/consume\" index=\"0\" isDefault=\"true\"/\u003e\n  \u003c/SPSSODescriptor\u003e\n  \u003cOrganization\u003e\n    \u003cOrganizationName xml:lang=\"en\"\u003eAcme, Inc\u003c/OrganizationName\u003e\n    \u003cOrganizationDisplayName xml:lang=\"en\"\u003eAcme, Inc\u003c/OrganizationDisplayName\u003e\n    \u003cOrganizationURL xml:lang=\"en\"\u003ehttps://www.example.com\u003c/OrganizationURL\u003e\n  \u003c/Organization\u003e\n  \u003cContactPerson contactType=\"technical\"\u003e\n    \u003cCompany\u003emailto:hi@example.com\u003c/Company\u003e\n  \u003c/ContactPerson\u003e\n\u003c/EntityDescriptor\u003e\n```\n\n### AuthnRequest\n\nTo generate an Authentication Request choose the desired binding from\nthe metadata and use it to serialize a request.\n\n```ruby\nidp = Saml::Kit::IdentityProviderMetadata.new(raw_xml)\nurl, saml_params = idp.login_request_for(binding: :http_post)\nputs [url, saml_params].inspect\n# [\"https://www.example.com/login\", {\"SAMLRequest\"=\u003e\"PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c2FtbHA6QXV0aG5SZXF1ZXN0IHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIHhtbG5zOnNhbWw9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iIElEPSJfN2Y0YjkxZGMtNTMyNi00NjgzLTgyOWItYWViNzlkNjM0ZWYzIiBWZXJzaW9uPSIyLjAiIElzc3VlSW5zdGFudD0iMjAxNy0xMi0xOVQwNDo0ODoxMloiIERlc3RpbmF0aW9uPSJodHRwczovL3d3dy5leGFtcGxlLmNvbS9sb2dpbiI+PHNhbWw6SXNzdWVyLz48c2FtbHA6TmFtZUlEUG9saWN5IEZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOm5hbWVpZC1mb3JtYXQ6cGVyc2lzdGVudCIvPjwvc2FtbHA6QXV0aG5SZXF1ZXN0Pg==\"}]\n```\n\n### Response\n\nTo generate a Response you will need a request object and the desired binding \nto serialize a response. You will also need to specify a user\nobject to create a response for.\n\n```ruby\nbinding = idp.single_sign_on_service_for(binding: :http_post)\nraw_params = Hash[uri.query.split(\"\u0026amp;\").map { |x| x.split(\"=\", 2) }].symbolize_keys\nsaml_request = binding.deserialize(raw_params)\n\nurl, saml_params = saml_request.response_for(user, binding: :http_post)\nputs [url, saml_params].inspect\n# [\"https://www.example.com/consume\", {\"SAMLResponse\"=\u003e\"PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48UmVzcG9uc2UgSUQ9Il9hZjFiNTg5Ni0wN2MzLTQ2Y2QtYTA5ZC0xOTRmZGNkNWZiZmYiIFZlcnNpb249IjIuMCIgSXNzdWVJbnN0YW50PSIyMDE3LTEyLTE5VDA1OjI5OjU0WiIgRGVzdGluYXRpb249Imh0dHBzOi8vd3d3LmV4YW1wbGUuY29tL2NvbnN1bWUiIENvbnNlbnQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpjb25zZW50OnVuc3BlY2lmaWVkIiBJblJlc3BvbnNlVG89Il9mYzg5MjllOC0zY2ZkLTQ5YmQtOTgzNi0xNTRhZGYzOTEzZjYiIHhtbG5zPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiPjxJc3N1ZXIgeG1sbnM9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iLz48U3RhdHVzPjxTdGF0dXNDb2RlIFZhbHVlPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6c3RhdHVzOlN1Y2Nlc3MiLz48L1N0YXR1cz48QXNzZXJ0aW9uIElEPSJfYjg4OWNmNzEtYTFmNS00ZWUxLWEzZTctMGM4ZTU5ZDY3ZTJkIiBJc3N1ZUluc3RhbnQ9IjIwMTctMTItMTlUMDU6Mjk6NTRaIiBWZXJzaW9uPSIyLjAiIHhtbG5zPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIj48SXNzdWVyLz48U3ViamVjdD48TmFtZUlEIEZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOm5hbWVpZC1mb3JtYXQ6cGVyc2lzdGVudCI+Yjk2ODE1MDA\n```\n\n### LogoutRequest\n\nTo create a logout request you will need to choose the desired binding\nfrom the metadata then generate a request for a specific user.\n\n```ruby\nclass User\n  attr_reader :id, :email\n\n  def initialize(id:, email:)\n    @id = id\n    @email = email\n  end\n\n  def name_id_for(name_id_format)\n    Saml::Kit::Namespaces::PERSISTENT == name_id_format ? id : email\n  end\n\n  def assertion_attributes_for(request)\n    request.trusted? ? { access_token: SecureRandom.uuid } : {}\n  end\nend\n\nuser = User.new(id: SecureRandom.uuid, email: \"hello@example.com\")\nidp = Saml::Kit::IdentityProviderMetadata.new(xml)\nurl, saml_params = idp.logout_request_for(user, binding: :http_post)\nputs [url, saml_params].inspect\n# [\"https://www.example.com/logout\", {\"SAMLRequest\"=\u003e\"PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48TG9nb3V0UmVxdWVzdCBJRD0iXzg3NjZiNTYyLTc2MzQtNDU4Zi04MzJmLTE4ODkwMjRlZDQ0MyIgVmVyc2lvbj0iMi4wIiBJc3N1ZUluc3RhbnQ9IjIwMTctMTItMTlUMDQ6NTg6MThaIiBEZXN0aW5hdGlvbj0iaHR0cHM6Ly93d3cuZXhhbXBsZS5jb20vbG9nb3V0IiB4bWxucz0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sIj48SXNzdWVyIHhtbG5zPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIi8+PE5hbWVJRCBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpuYW1laWQtZm9ybWF0OnBlcnNpc3RlbnQiIHhtbG5zPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIj5kODc3YWEzZS01YTUyLTRhODAtYTA3ZC1lM2U5YzBjNTA1Nzk8L05hbWVJRD48L0xvZ291dFJlcXVlc3Q+\"}]\n```\n\n### LogoutResponse\n\nTo generate a logout response, deserialize the logout request then\ngenerate a response from the request.\n\n```ruby\nidp = Saml::Kit::IdentityProviderMetadata.new(xml)\nraw_params = Hash[uri.query.split(\"\u0026amp;\").map { |x| x.split(\"=\", 2) }].symbolize_keys\n\nbinding = idp.single_logout_service_for(binding: :http_post)\nsaml_request = binding.deserialize(raw_params)\nurl, saml_params = saml_request.response_for(binding: :http_post)\nputs [url, saml_params].inspect\n# [\"https://www.example.com/logout\", {\"SAMLResponse\"=\u003e\"PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48TG9nb3V0UmVzcG9uc2UgeG1sbnM9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpwcm90b2NvbCIgSUQ9Il9kZDA2YmY5MC04ODI2LTQ5ZTMtYmYxNS1jYzAxMWJkNzU3NGEiIFZlcnNpb249IjIuMCIgSXNzdWVJbnN0YW50PSIyMDE3LTEyLTE5VDA1OjQyOjQyWiIgRGVzdGluYXRpb249Imh0dHBzOi8vd3d3LmV4YW1wbGUuY29tL2xvZ291dCIgSW5SZXNwb25zZVRvPSJfYmVhZjJiN2ItMDlmNC00ZmFkLWJkYmYtOWQ0ZDc1N2I5ZDU0Ij48SXNzdWVyIHhtbG5zPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIi8+PFN0YXR1cz48U3RhdHVzQ29kZSBWYWx1ZT0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnN0YXR1czpTdWNjZXNzIi8+PC9TdGF0dXM+PC9Mb2dvdXRSZXNwb25zZT4=\"}]\n```\n\n## Development\n\nAfter checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.\n\nTo install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).\n\n## Contributing\n\nBug reports and pull requests are welcome on Github at https://github.com/xlgmokha/saml-kit.\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxlgmokha%2Fsaml-kit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxlgmokha%2Fsaml-kit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxlgmokha%2Fsaml-kit/lists"}