https://github.com/hyperoslo/openid-token-proxy
Retrieves and refreshes OpenID tokens on behalf of a user when dealing with complex authentication schemes, such as client-side certificates
https://github.com/hyperoslo/openid-token-proxy
Last synced: about 1 year ago
JSON representation
Retrieves and refreshes OpenID tokens on behalf of a user when dealing with complex authentication schemes, such as client-side certificates
- Host: GitHub
- URL: https://github.com/hyperoslo/openid-token-proxy
- Owner: hyperoslo
- License: other
- Created: 2015-03-26T14:01:57.000Z (about 11 years ago)
- Default Branch: master
- Last Pushed: 2016-11-17T09:43:29.000Z (over 9 years ago)
- Last Synced: 2025-04-02T02:22:37.184Z (about 1 year ago)
- Language: Ruby
- Homepage:
- Size: 496 KB
- Stars: 6
- Watchers: 11
- Forks: 3
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE.md
Awesome Lists containing this project
README
# OpenID token proxy
[](https://rubygems.org/gems/openid-token-proxy)
[](https://travis-ci.org/hyperoslo/openid-token-proxy)
[](https://gemnasium.com/hyperoslo/openid-token-proxy)
[](https://codeclimate.com/github/hyperoslo/openid-token-proxy)
[](https://coveralls.io/r/hyperoslo/openid-token-proxy)
Retrieves and refreshes OpenID tokens on behalf of a user when dealing with complex
authentication schemes, such as client-side certificates.
**Supported Ruby versions: 2.0.0 or higher**
Licensed under the **MIT** license, see LICENSE for more information.
## Background
When using [OpenID](http://openid.net/specs/openid-connect-core-1_0.html) in
native applications, the most common approach is to open the identity provider's
authorization page in a web view, let the user authenticate and have the application
hold on to access, identity and refresh tokens.

However, the above flow may be unusable if the identity provider provides complex
authentication schemes, such as client-side certificates.
On 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).
On 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).

When using OpenID token proxy, the application opens a web browser - which has
access to client-side certificates regardless of storage location - and lets the
user authenticate. The identity provider redirects to the OpenID token proxy,
which in turn passes along any obtained tokens to the application.
## Installation
Add this line to your application's Gemfile:
```ruby
gem 'openid-token-proxy'
```
Or install it yourself:
$ gem install openid-token-proxy
## Usage
### Configuration
```ruby
OpenIDTokenProxy.configure do |config|
config.client_id = 'xxx'
config.client_secret = 'xxx'
config.issuer = 'https://login.windows.net/common'
config.redirect_uri = 'https://example.com/auth/callback'
config.resource = 'https://graph.windows.net'
# By default, only tokens issued for the resource above are accepted
# Alternatively, you can override the allowed audiences or allow multiple:
config.allowed_audiences = [
'https://id.hyper.no',
'https://graph.windows.net'
]
# Indicates which domain users will presumably be signing in with
config.domain_hint = 'example.com'
# Whether to force authentication in case a session is already established
config.prompt = 'login'
# If these endpoints or public keys are not configured explicitly, they will be
# discovered automatically by contacting the issuer (see above)
config.authorization_endpoint = 'https://login.windows.net/common/oauth2/authorize'
config.token_endpoint = 'https://login.windows.net/common/oauth2/token'
config.userinfo_endpoint = 'https://login.windows.net/common/openid/userinfo'
config.public_keys = [
OpenSSL::PKey::RSA.new("-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9...")
]
# Alternatively, you can override the authorization URI in its entirety:
config.authorization_uri = 'https://id.hyper.no/authorize?prompt=login'
end
```
Alternatively, these environment variables will be picked up automatically:
- `OPENID_ALLOWED_AUDIENCES` (comma-separated, defaults to `OPENID_RESOURCE`)
- `OPENID_AUTHORIZATION_ENDPOINT`
- `OPENID_AUTHORIZATION_URI`
- `OPENID_CLIENT_ID`
- `OPENID_CLIENT_SECRET`
- `OPENID_DOMAIN_HINT`
- `OPENID_ISSUER`
- `OPENID_PROMPT`
- `OPENID_REDIRECT_URI`
- `OPENID_RESOURCE`
- `OPENID_TOKEN_ENDPOINT`
- `OPENID_USERINFO_ENDPOINT`
### Token acquirement
OpenID token proxy's main task is to obtain tokens on behalf of users. To allow it
to do so, start by mounting the engine in your Rails application:
```ruby
Rails.application.routes.draw do
mount OpenIDTokenProxy::Engine, at: '/auth'
end
```
Next, register the engine's callback - `https://example.com/auth/callback` - as
the redirect URL of your OpenID application on the issuer so that any authorization
requests are routed back to your application.
The proxy itself also needs to be configured with a redirect URL in order for it
to know what to do with any newly obtained tokens. To boot back into a native
applicaton one could use custom URL schemes or intents:
```ruby
OpenIDTokenProxy.configure do |config|
config.token_acquirement_hook = proc { |token|
"my-app://?token=#{token}&refresh_token=#{token.refresh_token}"
}
end
```
**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.
### Token authentication
Additionally, OpenID token proxy ships with an authentication module simplifying
token validation for use in APIs:
```ruby
class AccountsController < ApplicationController
include OpenIDTokenProxy::Token::Authentication
require_valid_token
...
end
```
Access tokens may be provided with one of the following:
- `X-Token` header.
- `Authorization: Bearer ` header.
- Query string parameter `token`.
- Cookie `token`.
Token expiry time will be exposed through the `X-Token-Expiry-Time` header.
#### Identity / claims
A valid token is exposed to a controller as `current_token` and identity information
can be extracted by providing a claim name through hash-syntax:
```ruby
current_token['email']
```
Identity providers may support additional claims beyond the [standard OpenID ones](http://openid.net/specs/openid-connect-core-1_0.html#StandardClaims).
### Token refreshing
Most identity providers issue access tokens [with short lifespans](http://openid.net/specs/openid-connect-core-1_0.html#TokenLifetime).
To prevent users from having to authenticate often, refresh tokens are used to
obtain new access tokens without user intervention.
OpenID token proxy's token refresh module does just that:
```ruby
class AccountsController < ApplicationController
include OpenIDTokenProxy::Token::Authentication
include OpenIDTokenProxy::Token::Refresh
require_valid_token
...
end
```
Refresh tokens may be provided with one of the following:
- `X-Refresh-Token` header.
- Query string parameter `refresh_token`.
- Cookie `refresh_token`.
Whenever an access token has expired and a refresh token is given, the module will
attempt to obtain a new token transparently.
The following headers will be present on the API response if, **and only if**, a new
token was obtained:
- `X-Token` header containing the new access token to be used in future requests.
- `X-Refresh-Token` header containing the new refresh token.
You may configure some code to be run (scoped to a controller) when a token is
successfully refreshed:
```ruby
OpenIDTokenProxy.configure do |config|
config.token_refreshment_hook = proc { |token|
cookies[:token] = token.access_token
}
end
```
## Contributing
1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create a pull request
## Credits
Hyper made this. We're a digital communications agency with a passion for good code,
and if you're using this library we probably [want to hire you](http://hyper.no/jobs).