Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
/fositePublic

Extensible security first OAuth 2.0 and OpenID Connect SDK for Go.

License

NotificationsYou must be signed in to change notification settings

ory/fosite

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

ORY Fosite - Security-first OAuth2 framework

Build StatusCoverage StatusGo Report Card

Join the chat at https://www.ory.sh/chat

The security first OAuth2 & OpenID Connect framework forGo. Built simple, powerful and extensible. This libraryimplements peer-reviewedIETF RFC6749,counterfeits weaknesses covered in peer-reviewedIETF RFC6819 and countermeasures variousdatabase attack scenarios, keeping your application safe when that hackerpenetrates or leaks your database. OpenID Connect is implemented according toOpenID Connect Core 1.0 incorporating errata set 1and includes all flows: code, implicit, hybrid.

This library considered and implemented:

OAuth2 and OpenID Connect are difficult protocols. If you want quick wins, westrongly encourage you to look atHydra.Hydra is a secure, high performance, cloud native OAuth2 and OpenID Connectservice that integrates with every authentication method imaginable and is builton top of Fosite.

Table of Contents

Motivation

Fosite was written because our OAuth2 and OpenID Connect serviceHydra required a secure and extensibleOAuth2 library. We had to realize that nothing matching our requirements was outthere, so we decided to build it ourselves.

API Stability

The core public API is almost stable as most changes will only touch the innerworkings.

We strongly encourage vendoring fosite usingdep or comparable tools.

Example

The example does not have nice visuals but it should give you an idea of whatyou can do with Fosite and a few lines of code.

Authorize Code Grant

You can run this minimalistic example by doing

go get github.com/ory/fosite-examplecd $GOPATH/src/github.com/ory/fosite-exampledep ensurego install github.com/ory/fosite-examplefosite-example

There should be a server listening onlocalhost:3846.You can check out the example's source codehere.

A word on quality

We tried to set up as many tests as possible and test for as many cases coveredin the RFCs as possible. But we are only human. Please, feel free to add testsfor the various cases defined in the OAuth2 RFCs 6749 and 6819 or any othercases that improve the tests.

Everyone writing an RFC conform test that breaks with the currentimplementation, will receive a place in theHall of Fame!

A word on security

Please be aware that Fosite only secures parts of your server side security. Youstill need to secure your apps and clients, keep your tokens safe, prevent CSRFattacks, ensure database security, use valid and strong TLS certificates andmuch more. If you need any help or advice feel free to contact our securitystaff throughour website!

We have given the various specifications, especiallyOAuth 2.0 Threat Model and Security Considerations,a very close look and included everything we thought was in the scope of thisframework. Here is a complete list of things we implemented in Fosite:

Additionally, we added these safeguards:

  • Enforcing random states: Without a random-looking state or OpenID Connectnonce the request will fail.
  • Advanced Token Validation: Tokens are layouted as<key>.<signature>where<signature> is created using HMAC-SHA256 using a global secret. Thisis what a token can look like:/tgBeUhWlAT8tM8Bhmnx+Amf8rOYOUhrDi3pGzmjP7c=.BiV/Yhma+5moTP46anxMT6cWW8gz5R5vpC9RbpwSDdM=

Sections belowSection 5 thatare not covered in the list above should be reviewed by you. If you think that aspecific section should be something that is covered in Fosite, feel free tocreate anissue. Please be aware thatOpenID Connect requires specific knowledge of the identity provider, which iswhy Fosite only implements core requirements and most things must be implementedby you (for example prompt, max_age, ui_locales, id_token_hint, userauthentication, session management, ...).

It is strongly encouraged to use the handlers shipped with Fosite as theyfollow the specs and are well tested.

A word on extensibility

Fosite is extensible ... because OAuth2 is an extensible and flexibleframework. Fosite let's you register custom token and authorize endpointhandlers with the security that the requests have been validated against theOAuth2 specs beforehand. You can easily extend Fosite's capabilities. Forexample, if you want to provide OpenID Connect on top of your OAuth2 stack,that's no problem. Or custom assertions, what ever you like and as long as it issecure. ;)

Installation

Go 1.11+ must be installed on your system and it isrequired that you have set up your GOPATH environment variable.

go get -u github.com/ory/fosite/...

We recommend to usedep to mitigatecompatibility breaks that come with new api versions.

Documentation

There is an API documentation available atgodoc.org/ory/fosite.

Scopes

Fosite has three strategies for matching scopes. You can replace the defaultscope strategy if you need a custom one by implementingfosite.ScopeStrategy.

Using the composer, setting a strategy is easy:

import"github.com/ory/fosite"varconfig=&fosite.Config{ScopeStrategy:fosite.HierarchicScopeStrategy,}

Note: To issue refresh tokens with any of the grants, you need to includetheoffline scope in the OAuth2 request. This can be modified by theRefreshTokenScopes compose configuration. When set to an empty array,allgrants will issue refresh tokens.

fosite.WildcardScopeStrategy

This is the default strategy, and the safest one. It is best explained bylooking at some examples:

  • users.* matchesusers.read
  • users.* matchesusers.read.foo
  • users.read matchesusers.read
  • users does not matchusers.read
  • users.read.* does not matchusers.read
  • users.*.* does not matchusers.read
  • users.*.* matchesusers.read.own
  • users.*.* matchesusers.read.own.other
  • users.read.* matchesusers.read.own
  • users.read.* matchesusers.read.own.other
  • users.write.* does not matchusers.read.own
  • users.*.bar matchesusers.baz.bar
  • users.*.bar does notusers.baz.baz.bar

To requestusers.*, a client must have exactlyusers.* as granted scope.

fosite.ExactScopeStrategy

This strategy is searching only for exact matches. It returns true iff the scopeis granted.

fosite.HierarchicScopeStrategy

This strategy is deprecated, use it with care. Again, it is best explained bylooking at some examples:

  • users matchesusers
  • users matchesusers.read
  • users matchesusers.read.own
  • users.read matchesusers.read
  • users.read matchesusers.read.own
  • users.read does not matchusers.write
  • users.read does not matchusers.write.own

Globalization

Fosite does not natively carry translations for error messages and hints, butoffers an interface that allows the consumer to define catalog bundles and animplementation to translate. This is available through theMessageCatalog interface. The functions defined areself-explanatory. TheDefaultMessageCatalog illustrates this. Compose confighas been extended to take in an instance of theMessageCatalog.

Building translated files

There are three possible "message key" types:

  1. Value ofRFC6749Error.ErrorField: This is a string likeinvalid_requestand correlates to most errors produced by Fosite.
  2. Hint identifier passed intoRFC6749Error.WithHintIDOrDefaultf: This func isnot used extensively in Fosite but, in time, mostWithHint andWithHintfwill be replaced with this function.
  3. Free text string format passed intoRFC6749Error.WithHint andRFC6749Error.WithHintf: This function is used in Fosite and Hydraextensively and any message catalog implementation can use the format stringparameter as the message key.

An example of a message catalog can be seen in thei18n_test.go.

Generating theen messages file

This is a WIP at the moment, but effectively any scripting language can be usedto generate this. It would need to traverse all files in the source code andextract the possible message identifiers based on the different message keytypes.

Quickstart

Instantiating fosite by hand can be painful. Therefore we created a fewconvenience helpers available through thecompose package. It isstrongly encouraged to use these well tested composers.

In this very basic example, we will instantiate fosite with all OpenID Connectand OAuth2 handlers enabled. Please refer to theexample app for more details.

This little code snippet sets up a full-blown OAuth2 and OpenID Connect example.

package mainimport"github.com/ory/fosite"import"github.com/ory/fosite/compose"import"github.com/ory/fosite/storage"// This is the example storage that contains:// * an OAuth2 Client with id "my-client" and secrets "foobar" and "foobaz" capable of all oauth2 and open id connect grant and response types.// * a User for the resource owner password credentials grant type with username "peter" and password "secret".//// You will most likely replace this with your own logic once you set up a real world application.varstorage=storage.NewExampleStore()// This secret is being used to sign access and refresh tokens as well as// authorization codes. It must be exactly 32 bytes long.varsecret= []byte("my super secret signing password")privateKey,err:=rsa.GenerateKey(rand.Reader,2048)iferr!=nil {panic("unable to create private key")}// check the api docs of fosite.Config for further configuration optionsvarconfig=&fosite.Config{AccessTokenLifespan:time.Minute*30,GlobalSecret:secret,// ...}varoauth2Provider=compose.ComposeAllEnabled(config,storage,privateKey)// The authorize endpoint is usually at "https://mydomain.com/oauth2/auth".funcauthorizeHandlerFunc(rw http.ResponseWriter,req*http.Request) {// This context will be passed to all methods. It doesn't fulfill a real purpose in the standard library but could be used// to abort database lookups or similar things.ctx:=req.Context()// Let's create an AuthorizeRequest object!// It will analyze the request and extract important information like scopes, response type and others.ar,err:=oauth2Provider.NewAuthorizeRequest(ctx,req)iferr!=nil {oauth2Provider.WriteAuthorizeError(ctx,rw,ar,err)return}// Normally, this would be the place where you would check if the user is logged in and gives his consent.// We're simplifying things and just checking if the request includes a valid username and passwordifreq.Form.Get("username")!="peter" {rw.Header().Set("Content-Type","text/html;charset=UTF-8")rw.Write([]byte(`<h1>Login page</h1>`))rw.Write([]byte(`<p>Howdy! This is the log in page. For this example, it is enough to supply the username.</p><form method="post"><input type="text" name="username" /> <small>try peter</small><br><input type="submit"></form>`))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)iferr!=nil {oauth2Provider.WriteAuthorizeError(ctx,rw,ar,err)return}// Awesome, now we redirect back to the client redirect uri and pass along an authorize codeoauth2Provider.WriteAuthorizeResponse(ctx,rw,ar,response)}// The token endpoint is usually at "https://mydomain.com/oauth2/token"functokenHandlerFunc(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)iferr!=nil {oauth2Provider.WriteAccessError(ctx,rw,accessRequest,err)return}ifmySessionData.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)iferr!=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}funcsomeResourceProviderHandlerFunc(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)iferr!=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.
  • If you want to check out how to enable specific handlers, check out theintegration tests.

If you have working examples yourself, please share them with us!

Example Storage Implementation

Fosite does not ship a storage implementation. This is intended, becauserequirements vary with every environment. You can find a referenceimplementation atstorage/memory.go. This storage fulfillsrequirements from all OAuth2 and OpenID Connect handlers.

Extensible handlers

OAuth2 is a framework. Fosite mimics this behaviour by enabling you to replaceexisting or create new OAuth2 handlers. Of course, fosite ships handlers for allOAuth2 and OpenID Connect flows.

This section is missing documentation and we welcome any contributions in thatdirection.

JWT Introspection

Please note that when using the OAuth2StatelessJWTIntrospectionFactory accesstoken revocation is not possible.

Contribute

You need git and golang installed on your system.

go get -d github.com/ory/fositecd $GOPATH/src/github.com/ory/fositegit statusgit remote add myfork <url-to-your-fork>go test ./...

Simple, right? Now you are ready to go! Make sure to rungo test ./... often,detecting problems with your code rather sooner than later. Please read[CONTRIBUTE.md] before creating pull requests and issues.

Refresh mock objects

Run./generate-mocks.sh in fosite's root directory or run the contents of[generate-mocks.sh] in a shell.

Hall of Fame

This place is reserved for the fearless bug hunters, reviewers and contributors(alphabetical order).

Find out more about theauthor of Fosite and Hydra, andtheOry Company.


[8]ページ先頭

©2009-2025 Movatter.jp