diff --git a/README.md b/README.md index 785a930a..7595f596 100644 --- a/README.md +++ b/README.md @@ -1,519 +1,14 @@ -
+[![Build Status](https://github.com/canonical/fosite/actions/workflows/test.yml/badge.svg?branch=canonical)](https://github.com/canonical/fosite/actions/workflows/test.yml/badge.svg?branch=canonical) -[![Build Status](https://travis-ci.org/ory/fosite.svg?branch=master)](https://travis-ci.org/ory/fosite?branch=master) -[![Coverage Status](https://coveralls.io/repos/ory/fosite/badge.svg?branch=master&service=github&foo)](https://coveralls.io/github/ory/fosite?branch=master) -[![Go Report Card](https://goreportcard.com/badge/ory/fosite)](https://goreportcard.com/report/ory/fosite) +This is a fork of [Ory Fosite](https://github.com/ory/fosite). The reason for +forking fosite is that we needed to support the +[OAuth 2.0 Device Authorization Grant](https://datatracker.ietf.org/doc/html/rfc8628). +Some work was already done on upstream fosite, but the PRs were never merged. +Our implementation is heavily influnced by the work done on +https://github.com/ory/fosite/pull/701 from: -[![Join the chat at https://www.ory.sh/chat](https://img.shields.io/badge/join-chat-00cc99.svg)](https://www.ory.sh/chat) +- [supercairos](https://github.com/supercairos) +- [BuzzBumbleBee](https://github.com/BuzzBumbleBee) -**The security first OAuth2 & OpenID Connect framework for -[Go](https://golang.org).** Built simple, powerful and extensible. This library -implements peer-reviewed [IETF RFC6749](https://tools.ietf.org/html/rfc6749), -counterfeits weaknesses covered in peer-reviewed -[IETF RFC6819](https://tools.ietf.org/html/rfc6819) and countermeasures various -database attack scenarios, keeping your application safe when that hacker -penetrates or leaks your database. OpenID Connect is implemented according to -[OpenID Connect Core 1.0 incorporating errata set 1](https://openid.net/specs/openid-connect-core-1_0.html) -and includes all flows: code, implicit, hybrid. - -This library considered and implemented: - -- [The OAuth 2.0 Authorization Framework](https://tools.ietf.org/html/rfc6749) -- [OAuth 2.0 Multiple Response Type Encoding Practices](https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html) -- [OAuth 2.0 Threat Model and Security Considerations](https://tools.ietf.org/html/rfc6819) -- [Proof Key for Code Exchange by OAuth Public Clients](https://tools.ietf.org/html/rfc7636) -- [OAuth 2.0 for Native Apps](https://tools.ietf.org/html/rfc8252) -- [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html) -- [OAuth 2.0 Pushed Authorization Request](https://datatracker.ietf.org/doc/html/rfc9126) - -OAuth2 and OpenID Connect are difficult protocols. If you want quick wins, we -strongly encourage you to look at [Hydra](https://github.com/ory-am/hydra). -Hydra is a secure, high performance, cloud native OAuth2 and OpenID Connect -service that integrates with every authentication method imaginable and is built -on top of Fosite. - - - - -**Table of Contents** - -- [Motivation](#motivation) -- [API Stability](#api-stability) -- [Example](#example) -- [A word on quality](#a-word-on-quality) -- [A word on security](#a-word-on-security) -- [A word on extensibility](#a-word-on-extensibility) -- [Installation](#installation) -- [Documentation](#documentation) - - [Scopes](#scopes) - - [`fosite.WildcardScopeStrategy`](#fositewildcardscopestrategy) - - [`fosite.HierarchicScopeStrategy`](#fositehierarchicscopestrategy) - - [Quickstart](#quickstart) - - [Code Examples](#code-examples) - - [Example Storage Implementation](#example-storage-implementation) - - [Extensible handlers](#extensible-handlers) - - [JWT Introspection](#jwt-introspection) -- [Contribute](#contribute) - - [Refresh mock objects](#refresh-mock-objects) -- [Hall of Fame](#hall-of-fame) - - - -## Motivation - -Fosite was written because our OAuth2 and OpenID Connect service -[**Hydra**](https://github.com/ory-am/hydra) required a secure and extensible -OAuth2 library. We had to realize that nothing matching our requirements was out -there, so we decided to build it ourselves. - -## API Stability - -The core public API is almost stable as most changes will only touch the inner -workings. - -We strongly encourage vendoring fosite using -[dep](https://github.com/golang/dep) or comparable tools. - -## Example - -The example does not have nice visuals but it should give you an idea of what -you can do with Fosite and a few lines of code. - -![Authorize Code Grant](docs/authorize-code-grant.gif) - -You can run this minimalistic example by doing - -``` -go get github.com/ory/fosite-example -cd $GOPATH/src/github.com/ory/fosite-example -dep ensure -go install github.com/ory/fosite-example -fosite-example -``` - -There should be a server listening on [localhost:3846](https://localhost:3846/). -You can check out the example's source code -[here](https://github.com/ory/fosite-example/). - -## A word on quality - -We tried to set up as many tests as possible and test for as many cases covered -in the RFCs as possible. But we are only human. Please, feel free to add tests -for the various cases defined in the OAuth2 RFCs 6749 and 6819 or any other -cases that improve the tests. - -**Everyone** writing an RFC conform test that breaks with the current -implementation, will receive a place in the [Hall of Fame](#hall-of-fame)! - -## A word on security - -Please be aware that Fosite only secures parts of your server side security. You -still need to secure your apps and clients, keep your tokens safe, prevent CSRF -attacks, ensure database security, use valid and strong TLS certificates and -much more. If you need any help or advice feel free to contact our security -staff through [our website](https://ory.am/)! - -We have given the various specifications, especially -[OAuth 2.0 Threat Model and Security Considerations](https://tools.ietf.org/html/rfc6819#section-5.1.5.3), -a very close look and included everything we thought was in the scope of this -framework. Here is a complete list of things we implemented in Fosite: - -- [No Cleartext Storage of Credentials](https://tools.ietf.org/html/rfc6819#section-5.1.4.1.3) -- [Encryption of Credentials](https://tools.ietf.org/html/rfc6819#section-5.1.4.1.4) -- [Use Short Expiration Time](https://tools.ietf.org/html/rfc6819#section-5.1.5.3) -- [Limit Number of Usages or One-Time Usage](https://tools.ietf.org/html/rfc6819#section-5.1.5.4) -- [Bind Token to Client id](https://tools.ietf.org/html/rfc6819#section-5.1.5.8) -- [Automatic Revocation of Derived Tokens If Abuse Is Detected](https://tools.ietf.org/html/rfc6819#section-5.2.1.1) -- [Binding of Refresh Token to "client_id"](https://tools.ietf.org/html/rfc6819#section-5.2.2.2) -- [Refresh Token Rotation](https://tools.ietf.org/html/rfc6819#section-5.2.2.3) -- [Revocation of Refresh Tokens](https://tools.ietf.org/html/rfc6819#section-5.2.2.4) -- [Validate Pre-Registered "redirect_uri"](https://tools.ietf.org/html/rfc6819#section-5.2.3.5) -- [Binding of Authorization "code" to "client_id"](https://tools.ietf.org/html/rfc6819#section-5.2.4.4) -- [Binding of Authorization "code" to "redirect_uri"](https://tools.ietf.org/html/rfc6819#section-5.2.4.6) -- [Opaque access tokens](https://tools.ietf.org/html/rfc6749#section-1.4) -- [Opaque refresh tokens](https://tools.ietf.org/html/rfc6749#section-1.5) -- [Ensure Confidentiality of Requests](https://tools.ietf.org/html/rfc6819#section-5.1.1) -- [Use of Asymmetric Cryptography](https://tools.ietf.org/html/rfc6819#section-5.1.4.1.5) - Fosite ensures that redirect URIs use https **except localhost** but you need - to implement TLS for the token and auth endpoints yourself. - -Additionally, we added these safeguards: - -- **Enforcing random states:** Without a random-looking state or OpenID Connect - nonce the request will fail. -- **Advanced Token Validation:** Tokens are layouted as `Howdy! This is the log in page. For this example, it is enough to supply the username.
- - `)) - return - } - - // Now that the user is authorized, we set up a session. When validating / looking up tokens, we additionally get - // the session. You can store anything you want in it. - - // The session will be persisted by the store and made available when e.g. validating tokens or handling token endpoint requests. - // The default OAuth2 and OpenID Connect handlers require the session to implement a few methods. Apart from that, the - // session struct can be anything you want it to be. - mySessionData := &fosite.DefaultSession{ - Username: req.Form.Get("username"), - } - - // It's also wise to check the requested scopes, e.g.: - // if authorizeRequest.GetScopes().Has("admin") { - // http.Error(rw, "you're not allowed to do that", http.StatusForbidden) - // return - // } - - // Now we need to get a response. This is the place where the AuthorizeEndpointHandlers kick in and start processing the request. - // NewAuthorizeResponse is capable of running multiple response type handlers which in turn enables this library - // to support open id connect. - response, err := oauth2Provider.NewAuthorizeResponse(ctx, ar, mySessionData) - if err != nil { - oauth2Provider.WriteAuthorizeError(ctx, rw, ar, err) - return - } - - // Awesome, now we redirect back to the client redirect uri and pass along an authorize code - oauth2Provider.WriteAuthorizeResponse(ctx, rw, ar, response) -} - -// The token endpoint is usually at "https://mydomain.com/oauth2/token" -func tokenHandlerFunc(rw http.ResponseWriter, req *http.Request) { - ctx := req.Context() - - // Create an empty session object that will be passed to storage implementation to populate (unmarshal) the session into. - // By passing an empty session object as a "prototype" to the store, the store can use the underlying type to unmarshal the value into it. - // For an example of storage implementation that takes advantage of that, see SQL Store (fosite_store_sql.go) from ory/Hydra project. - mySessionData := new(fosite.DefaultSession) - - // This will create an access request object and iterate through the registered TokenEndpointHandlers to validate the request. - accessRequest, err := oauth2Provider.NewAccessRequest(ctx, req, mySessionData) - if err != nil { - oauth2Provider.WriteAccessError(ctx, rw, accessRequest, err) - return - } - - if mySessionData.Username == "super-admin-guy" { - // do something... - } - - // Next we create a response for the access request. Again, we iterate through the TokenEndpointHandlers - // and aggregate the result in response. - response, err := oauth2Provider.NewAccessResponse(ctx, accessRequest) - if err != nil { - oauth2Provider.WriteAccessError(ctx, rw, accessRequest, err) - return - } - - // All done, send the response. - oauth2Provider.WriteAccessResponse(ctx, rw, accessRequest, response) - - // The client has a valid access token now -} - -func someResourceProviderHandlerFunc(rw http.ResponseWriter, req *http.Request) { - ctx := req.Context() - requiredScope := "blogposts.create" - - _, ar, err := oauth2Provider.IntrospectToken(ctx, fosite.AccessTokenFromRequest(req), fosite.AccessToken, new(fosite.DefaultSession), requiredScope) - if err != nil { - // ... - } - - // If no error occurred the token + scope is valid and you have access to: - // ar.GetClient().GetID(), ar.GetGrantedScopes(), ar.GetScopes(), ar.GetSession().UserID, ar.GetRequestedAt(), ... -} -``` - -### Code Examples - -Fosite provides integration tests as well as a http server example: - -- Fosite ships with an example app that runs in your browser: - [Example app](https://github.com/ory/fosite-example/). -- If you want to check out how to enable specific handlers, check out the - [integration tests](integration/). - -If you have working examples yourself, please share them with us! - -### Example Storage Implementation - -Fosite does not ship a storage implementation. This is intended, because -requirements vary with every environment. You can find a reference -implementation at [storage/memory.go](storage/memory.go). This storage fulfills -requirements from all OAuth2 and OpenID Connect handlers. - -### Extensible handlers - -OAuth2 is a framework. Fosite mimics this behaviour by enabling you to replace -existing or create new OAuth2 handlers. Of course, fosite ships handlers for all -OAuth2 and OpenID Connect flows. - -- **[Fosite OAuth2 Core Handlers](handler/oauth2)** implement the - [Client Credentials Grant](https://tools.ietf.org/html/rfc6749#section-4.4), - [Resource Owner Password Credentials Grant](https://tools.ietf.org/html/rfc6749#section-4.3), - [Implicit Grant](https://tools.ietf.org/html/rfc6749#section-4.2), - [Authorization Code Grant](https://tools.ietf.org/html/rfc6749#section-4.1), - [Refresh Token Grant](https://tools.ietf.org/html/rfc6749#section-6) -- **[Fosite OpenID Connect Handlers](handler/openid)** implement the - [Authentication using the Authorization Code Flow](http://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth), - [Authentication using the Implicit Flow](http://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth), - [Authentication using the Hybrid Flow](http://openid.net/specs/openid-connect-core-1_0.html#HybridFlowAuth) - -This section is missing documentation and we welcome any contributions in that -direction. - -### JWT Introspection - -Please note that when using the OAuth2StatelessJWTIntrospectionFactory access -token revocation is not possible. - -## Contribute - -You need git and golang installed on your system. - -``` -go get -d github.com/ory/fosite -cd $GOPATH/src/github.com/ory/fosite -git status -git remote add myfork