README.md in rodauth-oauth-0.0.6 vs README.md in rodauth-oauth-0.1.0
- old
+ new
@@ -1,15 +1,15 @@
# Rodauth::Oauth
-[![pipeline status](https://gitlab.com/honeyryderchuck/rodauth-oauth/badges/master/pipeline.svg)](https://gitlab.com/honeyryderchuck/rodauth-oauth/-/commits/master)
-[![coverage report](https://gitlab.com/honeyryderchuck/rodauth-oauth/badges/master/coverage.svg)](https://gitlab.com/honeyryderchuck/rodauth-oauth/-/commits/master)
+[![pipeline status](https://gitlab.com/honeyryderchuck/rodauth-oauth/badges/master/pipeline.svg)](https://gitlab.com/honeyryderchuck/rodauth-oauth/-/pipelines?page=1&ref=master)
+[![coverage report](https://gitlab.com/honeyryderchuck/rodauth-oauth/badges/master/coverage.svg)](https://honeyryderchuck.gitlab.io/rodauth-oauth/coverage/#_AllFiles)
This is an extension to the `rodauth` gem which implements the [OAuth 2.0 framework](https://tools.ietf.org/html/rfc6749) for an authorization server.
## Features
-This gem implements:
+This gem implements the following RFCs and features of OAuth:
* [The OAuth 2.0 protocol framework](https://tools.ietf.org/html/rfc6749):
* [Authorization grant flow](https://tools.ietf.org/html/rfc6749#section-1.3);
* [Access Token generation](https://tools.ietf.org/html/rfc6749#section-1.4);
* [Access Token refresh](https://tools.ietf.org/html/rfc6749#section-1.5);
@@ -22,10 +22,12 @@
* [MAC Authentication Scheme](https://tools.ietf.org/html/draft-hammer-oauth-v2-mac-token-02);
* [JWT Acess Tokens](https://tools.ietf.org/html/draft-ietf-oauth-access-token-jwt-07);
* [JWT Secured Authorization Requests](https://tools.ietf.org/html/draft-ietf-oauth-jwsreq-20);
* OAuth application and token management dashboards;
+It also implements the [OpenID Connect layer](https://openid.net/connect/) on top of the OAuth features it provides.
+
This gem supports also rails (through [rodauth-rails]((https://github.com/janko/rodauth-rails))).
## Installation
@@ -41,10 +43,19 @@
Or install it yourself as:
$ gem install rodauth-oauth
+
+## Resources
+| | |
+| ------------- | ----------------------------------------------------------- |
+| Website | https://honeyryderchuck.gitlab.io/rodauth-oauth/ |
+| Documentation | https://honeyryderchuck.gitlab.io/rodauth-oauth/rdoc/ |
+| Wiki | https://gitlab.com/honeyryderchuck/rodauth-oauth/wikis/home |
+| CI | https://gitlab.com/honeyryderchuck/rodauth-oauth/pipelines |
+
## Usage
This tutorial assumes you already read the documentation and know how to set up `rodauth`. After that, integrating `roda-auth` will look like:
```ruby
@@ -84,12 +95,23 @@
end
end
end
```
-You'll have to do a bit more boilerplate, so here's the instructions.
+For OpenID, it's very similar to the example above:
+
+```ruby
+plugin :rodauth do
+ # enable it in the plugin
+ enable :login, :openid
+ oauth_application_default_scope %w[openid]
+ oauth_application_scopes %w[openid email profile]
+end
+```
+
+
### Example (TL;DR)
If you're familiar with the technology and want to skip the next paragraphs, just [check our example applications](https://gitlab.com/honeyryderchuck/rodauth-oauth/-/tree/master/examples/).
@@ -99,11 +121,11 @@
##### HTTPX
```ruby
require "httpx"
-response = HTTPX.post("https://auth_server/oauth-token",json: {
+response = HTTPX.post("https://auth_server/token",json: {
client_id: ENV["OAUTH_CLIENT_ID"],
client_secret: ENV["OAUTH_CLIENT_SECRET"],
grant_type: "authorization_code",
code: "oiweicnewdh32fhoi3hf3ihfo2ih3f2o3as"
})
@@ -113,22 +135,22 @@
```
##### cURL
```
-> curl --data '{"client_id":"$OAUTH_CLIENT_ID","client_secret":"$OAUTH_CLIENT_SECRET","grant_type":"authorization_code","code":"oiweicnewdh32fhoi3hf3ihfo2ih3f2o3as"}' https://auth_server/oauth-token
+> curl --data '{"client_id":"$OAUTH_CLIENT_ID","client_secret":"$OAUTH_CLIENT_SECRET","grant_type":"authorization_code","code":"oiweicnewdh32fhoi3hf3ihfo2ih3f2o3as"}' https://auth_server/token
```
#### Refresh Token
Refreshing expired tokens also happens mostly server-to-server, here's an example:
##### HTTPX
```ruby
require "httpx"
-response = HTTPX.post("https://auth_server/oauth-token",json: {
+response = HTTPX.post("https://auth_server/token",json: {
client_id: ENV["OAUTH_CLIENT_ID"],
client_secret: ENV["OAUTH_CLIENT_SECRET"],
grant_type: "refresh_token",
token: "2r89hfef4j9f90d2j2390jf390g"
})
@@ -138,22 +160,22 @@
```
##### cURL
```
-> curl -H "X-your-auth-scheme: $SERVER_KEY" --data '{"client_id":"$OAUTH_CLIENT_ID","client_secret":"$OAUTH_CLIENT_SECRET","grant_type":"token","token":"2r89hfef4j9f90d2j2390jf390g"}' https://auth_server/oauth-token
+> curl -H "X-your-auth-scheme: $SERVER_KEY" --data '{"client_id":"$OAUTH_CLIENT_ID","client_secret":"$OAUTH_CLIENT_SECRET","grant_type":"token","token":"2r89hfef4j9f90d2j2390jf390g"}' https://auth_server/token
```
#### Revoking tokens
Token revocation can be done both by the idenntity owner or the application owner, and can therefore be done either online (browser-based form) or server-to-server. Here's an example using server-to-server:
```ruby
require "httpx"
httpx = HTTPX.plugin(:basic_authorization)
response = httpx.basic_authentication(ENV["CLIENT_ID"], ENV["CLIENT_SECRET"])
- .post("https://auth_server/oauth-revoke",json: {
+ .post("https://auth_server/revoke",json: {
token_type_hint: "access_token", # can also be "refresh:tokn"
token: "2r89hfef4j9f90d2j2390jf390g"
})
response.raise_for_status
payload = JSON.parse(response.to_s)
@@ -161,22 +183,22 @@
```
##### cURL
```
-> curl -H "X-your-auth-scheme: $SERVER_KEY" --data '{"client_id":"$OAUTH_CLIENT_ID","token_type_hint":"access_token","token":"2r89hfef4j9f90d2j2390jf390g"}' https://auth_server/oauth-revoke
+> curl -H "X-your-auth-scheme: $SERVER_KEY" --data '{"client_id":"$OAUTH_CLIENT_ID","token_type_hint":"access_token","token":"2r89hfef4j9f90d2j2390jf390g"}' https://auth_server/revoke
```
#### Token introspection
Token revocation can be used to determine the state of a token (whether active, what's the scope...) . Here's an example using server-to-server:
```ruby
require "httpx"
httpx = HTTPX.plugin(:basic_authorization)
response = httpx.basic_authentication(ENV["CLIENT_ID"], ENV["CLIENT_SECRET"])
- .post("https://auth_server/oauth-introspect",json: {
+ .post("https://auth_server/introspect",json: {
token_type_hint: "access_token", # can also be "refresh:tokn"
token: "2r89hfef4j9f90d2j2390jf390g"
})
response.raise_for_status
payload = JSON.parse(response.to_s)
@@ -184,11 +206,11 @@
```
##### cURL
```
-> curl -H "X-your-auth-scheme: $SERVER_KEY" --data '{"client_id":"$OAUTH_CLIENT_ID","token_type_hint":"access_token","token":"2r89hfef4j9f90d2j2390jf390g"}' https://auth_server/oauth-revoke
+> curl -H "X-your-auth-scheme: $SERVER_KEY" --data '{"client_id":"$OAUTH_CLIENT_ID","token_type_hint":"access_token","token":"2r89hfef4j9f90d2j2390jf390g"}' https://auth_server/revoke
```
### Authorization Server Metadata
The Authorization Server Metadata endpoint can be used by clients to obtain the information needed to interact with an
@@ -241,14 +263,14 @@
### Endpoints
Once you set it up, by default, the following endpoints will be available:
-* `GET /oauth-authorize`: Loads the OAuth authorization HTML form;
-* `POST /oauth-authorize`: Responds to an OAuth authorization request, as [per the spec](https://tools.ietf.org/html/rfc6749#section-4);
-* `POST /oauth-token`: Generates OAuth tokens as [per the spec](https://tools.ietf.org/html/rfc6749#section-4.4.2);
-* `POST /oauth-revoke`: Revokes OAuth tokens as [per the spec](https://tools.ietf.org/html/rfc7009);
+* `GET /authorize`: Loads the OAuth authorization HTML form;
+* `POST /authorize`: Responds to an OAuth authorization request, as [per the spec](https://tools.ietf.org/html/rfc6749#section-4);
+* `POST /token`: Generates OAuth tokens as [per the spec](https://tools.ietf.org/html/rfc6749#section-4.4.2);
+* `POST /revoke`: Revokes OAuth tokens as [per the spec](https://tools.ietf.org/html/rfc7009);
### OAuth applications
This feature is **optional**, as not all authorization servers will want a full oauth applications dashboard. However, if you do and you don't want to do the work yourself, you can set it up in your roda app like this:
@@ -424,11 +446,11 @@
The "Proof Key for Code Exchange by OAuth Public Clients" (aka PKCE) flow, which is **particularly recommended for OAuth integration in mobile apps**, is transparently supported by `rodauth-oauth`, by adding the `code_challenge_method=S256&code_challenge=$YOUR_CODE_CHALLENGE` query params to the authorization url. Once you do that, you'll have to pass the `code_verifier` when generating a token:
```ruby
# with httpx
require "httpx"
-response = HTTPX.post("https://auth_server/oauth-token",json: {
+response = HTTPX.post("https://auth_server/token",json: {
client_id: ENV["OAUTH_CLIENT_ID"],
grant_type: "authorization_code",
code: "oiweicnewdh32fhoi3hf3ihfo2ih3f2o3as",
code_verifier: your_code_verifier_here
})
@@ -475,11 +497,11 @@
Generating an access token will deliver the following fields:
```ruby
# with httpx
require "httpx"
-response = httpx.post("https://auth_server/oauth-token",json: {
+response = httpx.post("https://auth_server/token",json: {
client_id: env["oauth_client_id"],
client_secret: env["oauth_client_secret"],
grant_type: "authorization_code",
code: "oiweicnewdh32fhoi3hf3ihfo2ih3f2o3as"
})
@@ -574,19 +596,19 @@
which adds an extra layer of protection.
#### JWKS URI
-A route is defined for getting the JWK Set in a JSON format; this is typically used by client applications, who need the JWK set to decode the JWT token. This URL is typically `https://oauth-server/oauth-jwks`.
+A route is defined for getting the JWK Set in a JSON format; this is typically used by client applications, who need the JWK set to decode the JWT token. This URL is typically `https://oauth-server/jwks`.
#### JWT Bearer as authorization grant
One can emit a new access token by using the bearer access token as grant. This can be done emitting a request similar to this:
```ruby
# with httpx
require "httpx"
-response = httpx.post("https://auth_server/oauth-token",json: {
+response = httpx.post("https://auth_server/token",json: {
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
assertion: "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOjEsImlzcyI6IkV4YW1wbGUiLCJpYXQiOjE1OTIwMDk1MDEsImNsaWVudF9pZCI6IkNMSUVOVF9JRCIsImV4cCI6MTU5MjAxMzEwMSwiYXVkIjpudWxsLCJzY29wZSI6InVzZXIucmVhZCB1c2VyLndyaXRlIiwianRpIjoiOGM1NTVjMjdiOWRjNDdmOTcyNWRkYzBhMjk0NzA1ZTA4NzFkY2JlN2Q5ZTNlMmVkNGE1ZTBiOGZlNTZlYzcxMSJ9.AlxKRtE3ec0mtyBSDx4VseND4eC6cH5ubtv8gfYxxsc"
})
response.raise_for_status
payload = json.parse(response.to_s)