https://github.com/janekolszak/idp
Identity provider for Hydra
https://github.com/janekolszak/idp
Last synced: 5 days ago
JSON representation
Identity provider for Hydra
- Host: GitHub
- URL: https://github.com/janekolszak/idp
- Owner: janekolszak
- License: mit
- Created: 2016-06-05T18:26:32.000Z (almost 9 years ago)
- Default Branch: master
- Last Pushed: 2017-06-12T21:49:21.000Z (almost 8 years ago)
- Last Synced: 2025-04-18T21:31:20.311Z (16 days ago)
- Language: Go
- Size: 5.81 MB
- Stars: 76
- Watchers: 5
- Forks: 17
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-ory - Ory Hydra Identity Provider
- awesome-ory - Ory Hydra Identity Provider
README
# Identity Provider (IdP) for Hydra
[](https://travis-ci.org/janekolszak/idp) [](https://codeclimate.com/github/janekolszak/idp) [](https://godoc.org/github.com/janekolszak/idp) [](https://gitter.im/janekolszak/idp)This is a helper library for handling *challenge* requests from [Hydra](https://github.com/ory/hydra), it handles:
- Storing challenge in a short lived cookie instead of query parameters
- Passing user's consent to Hydra
- Retriving keys from Hydra and using them for JWT verification
- Caching keys and client info**IdP uses [Gorilla sessions](http://www.gorillatoolkit.org/pkg/sessions) as the Store. There are many Gorilla sessions backend implementations out there.**
## About
Let's say we have an Identity Provider with:
- **/login** endpoint that accepts Hydra's challenges
- **/consent** endpoint that handles getting consent from the userThis is how challenge request could be hadled with the IdP library:

## Initialization
There are many implementations of Gorilla sessions. Let's use Postgres as the backend:
```go
import (
"github.com/janekolszak/idp"
"github.com/antonlindstrom/pgstore"
"time"
)func main() {
challengeCookieStore, err = pgstore.NewPGStore("postgres://user:pass@address/dbname", []byte("secret"))
// Return on error// Create the IDP
IDP := idp.NewIDP(&idp.IDPConfig{
ClusterURL: /* Hydra's address */,
ClientID: /* IDP's client ID */,
ClientSecret: /* IDP's client secret */,
KeyCacheExpiration: time.Duration(/* Key expiration time */) * time.Second,
ClientCacheExpiration: time.Duration(/* Client info expiration */) * time.Second,
CacheCleanupInterval: time.Duration(/* Cache cleanup interval. Eg. 30 */) * time.Second,
ChallengeExpiration: time.Duration(/* Challenge cookie expiration. Eg. 10 */) * time.Minutes,
ChallengeStore: challengeCookieStore,
})// Connects with Hydra and fills caches
err = IDP.Connect(true /*TLS verification*/)
// Return on error}
```
## Usage
```go
func HandleChallengeGET(w http.ResponseWriter, r *http.Request) {
// 0. Render HTML page with a login form
}func HandleChallengePOST(w http.ResponseWriter, r *http.Request) {
// 0. Parse and validate login data (username:password, login cookie etc)
// Return on error// 1. Verify user's credentials (eg. check username:password).
// Return on error
// Obtain userid// 2. Create a Challenge
challenge, err := IDP.NewChallenge(r, userid)
// Return on error// 3. Save the Challenge to a cookie with a small TTL
err = challenge.Save(w, r)
// Return on error// 4. Redirect to the consent endpoint
}// Displays Consent screen. Here user agrees for listed scopes
func HandleConsentGET(w http.ResponseWriter, r *http.Request) {// 0. Get the Challenge from the cookie
challenge, err := IDP.GetChallenge(r)
// Return on error// 1. Display consent screen
// Use challenge.User to get user's ID
// Use challenge.Scopes to display requested scopes// 2. If any error occured delete the Challenge cookie (optional)
if err != nil {
err = challenge.Delete(c.Writer, c.Request)
}// 3. Render the HTML consent page
}func HandleConsentPOST(w http.ResponseWriter, r *http.Request) {
// 0. Get the Challenge from the cookie
challenge, err := IDP.GetChallenge(c.Request)
// Return on error// 1. Parse and validate consent data (eg. form answer=y or list of scopes)
// Return on error// 2. If user refused access
err = challenge.RefuseAccess(w, r)
// Return// 3. If userf agreed to grant access
err = challenge.GrantAccessToAll(w, r)
// Return
}```