{"id":19319813,"url":"https://github.com/hyperoslo/openid-token-proxy","last_synced_at":"2025-04-22T17:32:20.007Z","repository":{"id":29395451,"uuid":"32930678","full_name":"hyperoslo/openid-token-proxy","owner":"hyperoslo","description":"Retrieves and refreshes OpenID tokens on behalf of a user when dealing with complex authentication schemes, such as client-side certificates","archived":false,"fork":false,"pushed_at":"2016-11-17T09:43:29.000Z","size":508,"stargazers_count":6,"open_issues_count":0,"forks_count":3,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-04-02T02:22:37.184Z","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":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hyperoslo.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-03-26T14:01:57.000Z","updated_at":"2016-11-17T09:43:29.000Z","dependencies_parsed_at":"2022-09-05T21:00:46.413Z","dependency_job_id":null,"html_url":"https://github.com/hyperoslo/openid-token-proxy","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyperoslo%2Fopenid-token-proxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyperoslo%2Fopenid-token-proxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyperoslo%2Fopenid-token-proxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyperoslo%2Fopenid-token-proxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hyperoslo","download_url":"https://codeload.github.com/hyperoslo/openid-token-proxy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250287715,"owners_count":21405670,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":"2024-11-10T01:25:21.660Z","updated_at":"2025-04-22T17:32:19.662Z","avatar_url":"https://github.com/hyperoslo.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# OpenID token proxy\n\n[![Gem Version](https://img.shields.io/gem/v/openid-token-proxy.svg?style=flat)](https://rubygems.org/gems/openid-token-proxy)\n[![Build Status](https://img.shields.io/travis/hyperoslo/openid-token-proxy.svg?style=flat)](https://travis-ci.org/hyperoslo/openid-token-proxy)\n[![Dependency Status](https://img.shields.io/gemnasium/hyperoslo/openid-token-proxy.svg?style=flat)](https://gemnasium.com/hyperoslo/openid-token-proxy)\n[![Code Climate](https://img.shields.io/codeclimate/github/hyperoslo/openid-token-proxy.svg?style=flat)](https://codeclimate.com/github/hyperoslo/openid-token-proxy)\n[![Coverage Status](https://img.shields.io/coveralls/hyperoslo/openid-token-proxy.svg?style=flat)](https://coveralls.io/r/hyperoslo/openid-token-proxy)\n\nRetrieves and refreshes OpenID tokens on behalf of a user when dealing with complex\nauthentication schemes, such as client-side certificates.\n\n**Supported Ruby versions: 2.0.0 or higher**\n\nLicensed under the **MIT** license, see LICENSE for more information.\n\n\n## Background\n\nWhen using [OpenID](http://openid.net/specs/openid-connect-core-1_0.html) in\nnative applications, the most common approach is to open the identity provider's\nauthorization page in a web view, let the user authenticate and have the application\nhold on to access, identity and refresh tokens.\n\n![Regular OpenID flow](docs/regular-openid-flow.png?raw=1)\n\nHowever, the above flow may be unusable if the identity provider provides complex\nauthentication schemes, such as client-side certificates.\n\nOn iOS, client-side certificates stored in the system keychain [cannot be obtained due to application sandboxing](http://stackoverflow.com/questions/7648487/how-to-list-certificates-from-the-iphone-keychain-inside-my-app).\n\nOn Android, one can obtain system certificates but these [can not be used within a web view](http://stackoverflow.com/questions/15588851/android-webview-with-client-certificate).\n\n![OpenID token proxy flow](docs/openid-token-proxy-flow.png?raw=1)\n\nWhen using OpenID token proxy, the application opens a web browser - which has\naccess to client-side certificates regardless of storage location - and lets the\nuser authenticate. The identity provider redirects to the OpenID token proxy,\nwhich in turn passes along any obtained tokens to the application.\n\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'openid-token-proxy'\n```\n\nOr install it yourself:\n\n    $ gem install openid-token-proxy\n\n\n## Usage\n\n### Configuration\n\n```ruby\nOpenIDTokenProxy.configure do |config|\n  config.client_id = 'xxx'\n  config.client_secret = 'xxx'\n  config.issuer = 'https://login.windows.net/common'\n  config.redirect_uri = 'https://example.com/auth/callback'\n  config.resource = 'https://graph.windows.net'\n\n  # By default, only tokens issued for the resource above are accepted\n  # Alternatively, you can override the allowed audiences or allow multiple:\n  config.allowed_audiences = [\n    'https://id.hyper.no',\n    'https://graph.windows.net'\n  ]\n\n  # Indicates which domain users will presumably be signing in with\n  config.domain_hint = 'example.com'\n\n  # Whether to force authentication in case a session is already established\n  config.prompt = 'login'\n\n  # If these endpoints or public keys are not configured explicitly, they will be\n  # discovered automatically by contacting the issuer (see above)\n  config.authorization_endpoint = 'https://login.windows.net/common/oauth2/authorize'\n  config.token_endpoint = 'https://login.windows.net/common/oauth2/token'\n  config.userinfo_endpoint = 'https://login.windows.net/common/openid/userinfo'\n  config.public_keys = [\n    OpenSSL::PKey::RSA.new(\"-----BEGIN PUBLIC KEY-----\\nMIIBIjANBgkqhkiG9...\")\n  ]\n\n  # Alternatively, you can override the authorization URI in its entirety:\n  config.authorization_uri = 'https://id.hyper.no/authorize?prompt=login'\nend\n```\n\nAlternatively, these environment variables will be picked up automatically:\n\n- `OPENID_ALLOWED_AUDIENCES` (comma-separated, defaults to `OPENID_RESOURCE`)\n- `OPENID_AUTHORIZATION_ENDPOINT`\n- `OPENID_AUTHORIZATION_URI`\n- `OPENID_CLIENT_ID`\n- `OPENID_CLIENT_SECRET`\n- `OPENID_DOMAIN_HINT`\n- `OPENID_ISSUER`\n- `OPENID_PROMPT`\n- `OPENID_REDIRECT_URI`\n- `OPENID_RESOURCE`\n- `OPENID_TOKEN_ENDPOINT`\n- `OPENID_USERINFO_ENDPOINT`\n\n\n### Token acquirement\n\nOpenID token proxy's main task is to obtain tokens on behalf of users. To allow it\nto do so, start by mounting the engine in your Rails application:\n\n```ruby\nRails.application.routes.draw do\n  mount OpenIDTokenProxy::Engine, at: '/auth'\nend\n```\n\nNext, register the engine's callback - `https://example.com/auth/callback` - as\nthe redirect URL of your OpenID application on the issuer so that any authorization\nrequests are routed back to your application.\n\nThe proxy itself also needs to be configured with a redirect URL in order for it\nto know what to do with any newly obtained tokens. To boot back into a native\napplicaton one could use custom URL schemes or intents:\n\n```ruby\nOpenIDTokenProxy.configure do |config|\n  config.token_acquirement_hook = proc { |token|\n    \"my-app://?token=#{token}\u0026refresh_token=#{token.refresh_token}\"\n  }\nend\n```\n\n**Warning**: Redirecting to any path with query parameters (e.g. `example.com/?token=xxx`) could theoretically leak tokens to third parties through the `Referer`-header for external assets.\n\n\n### Token authentication\n\nAdditionally, OpenID token proxy ships with an authentication module simplifying\ntoken validation for use in APIs:\n\n```ruby\nclass AccountsController \u003c ApplicationController\n  include OpenIDTokenProxy::Token::Authentication\n\n  require_valid_token\n\n  ...\nend\n```\n\nAccess tokens may be provided with one of the following:\n\n- `X-Token` header.\n- `Authorization: Bearer \u003ctoken\u003e` header.\n- Query string parameter `token`.\n- Cookie `token`.\n\nToken expiry time will be exposed through the `X-Token-Expiry-Time` header.\n\n\n#### Identity / claims\n\nA valid token is exposed to a controller as `current_token` and identity information\ncan be extracted by providing a claim name through hash-syntax:\n\n```ruby\ncurrent_token['email']\n```\n\nIdentity providers may support additional claims beyond the [standard OpenID ones](http://openid.net/specs/openid-connect-core-1_0.html#StandardClaims).\n\n\n### Token refreshing\n\nMost identity providers issue access tokens [with short lifespans](http://openid.net/specs/openid-connect-core-1_0.html#TokenLifetime).\nTo prevent users from having to authenticate often, refresh tokens are used to\nobtain new access tokens without user intervention.\n\nOpenID token proxy's token refresh module does just that:\n\n```ruby\nclass AccountsController \u003c ApplicationController\n  include OpenIDTokenProxy::Token::Authentication\n  include OpenIDTokenProxy::Token::Refresh\n\n  require_valid_token\n\n  ...\nend\n```\n\nRefresh tokens may be provided with one of the following:\n\n- `X-Refresh-Token` header.\n- Query string parameter `refresh_token`.\n- Cookie `refresh_token`.\n\nWhenever an access token has expired and a refresh token is given, the module will\nattempt to obtain a new token transparently.\n\nThe following headers will be present on the API response if, **and only if**, a new\ntoken was obtained:\n\n- `X-Token` header containing the new access token to be used in future requests.\n- `X-Refresh-Token` header containing the new refresh token.\n\nYou may configure some code to be run (scoped to a controller) when a token is\nsuccessfully refreshed:\n\n```ruby\nOpenIDTokenProxy.configure do |config|\n  config.token_refreshment_hook = proc { |token|\n    cookies[:token] = token.access_token\n  }\nend\n```\n\n\n## Contributing\n\n1. Fork it\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create a pull request\n\n\n## Credits\n\nHyper made this. We're a digital communications agency with a passion for good code,\nand if you're using this library we probably [want to hire you](http://hyper.no/jobs).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhyperoslo%2Fopenid-token-proxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhyperoslo%2Fopenid-token-proxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhyperoslo%2Fopenid-token-proxy/lists"}