{"id":17599616,"url":"https://github.com/janekolszak/idp","last_synced_at":"2025-04-30T06:27:29.870Z","repository":{"id":74989085,"uuid":"60474492","full_name":"janekolszak/idp","owner":"janekolszak","description":"Identity provider for Hydra","archived":false,"fork":false,"pushed_at":"2017-06-12T21:49:21.000Z","size":6097,"stargazers_count":76,"open_issues_count":0,"forks_count":17,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-18T21:31:20.311Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/janekolszak.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-06-05T18:26:32.000Z","updated_at":"2021-11-20T11:16:56.000Z","dependencies_parsed_at":"2023-06-18T07:45:35.444Z","dependency_job_id":null,"html_url":"https://github.com/janekolszak/idp","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/janekolszak%2Fidp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/janekolszak%2Fidp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/janekolszak%2Fidp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/janekolszak%2Fidp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/janekolszak","download_url":"https://codeload.github.com/janekolszak/idp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251653292,"owners_count":21622101,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-22T10:26:26.234Z","updated_at":"2025-04-30T06:27:29.846Z","avatar_url":"https://github.com/janekolszak.png","language":"Go","funding_links":[],"categories":["Archived, Outdated, and WIP"],"sub_categories":["Ory Fosite"],"readme":"# Identity Provider (IdP) for Hydra\n[![Build Status](https://travis-ci.org/janekolszak/idp.svg?branch=master)](https://travis-ci.org/janekolszak/idp) [![Code Climate](https://codeclimate.com/github/janekolszak/idp/badges/gpa.svg)](https://codeclimate.com/github/janekolszak/idp) [![GoDoc](https://godoc.org/github.com/janekolszak/idp?status.svg)](https://godoc.org/github.com/janekolszak/idp) [![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg?maxAge=2592000)](https://gitter.im/janekolszak/idp)\n\nThis is a helper library for handling *challenge* requests from [Hydra](https://github.com/ory/hydra), it handles:\n- Storing challenge in a short lived cookie instead of query parameters\n- Passing user's consent to Hydra\n- Retriving keys from Hydra and using them for JWT verification\n- Caching keys and client info\n\n**IdP uses [Gorilla sessions](http://www.gorillatoolkit.org/pkg/sessions) as the Store. There are many Gorilla sessions backend implementations out there.**\n\n## About\n\nLet's say we have an Identity Provider with:\n- **/login** endpoint that accepts Hydra's challenges\n- **/consent** endpoint that handles getting consent from the user\n\nThis is how challenge request could be hadled with the IdP library:\n\n![Sequence Diagram](https://raw.githubusercontent.com/janekolszak/idp/master/doc/sequenceDiagram.png)\n\n## Initialization\nThere are many implementations of Gorilla sessions. Let's use Postgres as the backend: \n```go\nimport (\n\t\"github.com/janekolszak/idp\"\n\t\"github.com/antonlindstrom/pgstore\"\n\t\"time\"\n)\n\nfunc main() {\n\tchallengeCookieStore, err = pgstore.NewPGStore(\"postgres://user:pass@address/dbname\", []byte(\"secret\"))\n\t// Return on error\n\n\t// Create the IDP\n\tIDP := idp.NewIDP(\u0026idp.IDPConfig{\n\t\tClusterURL:            /* Hydra's address */,\n\t\tClientID:              /* IDP's client ID */,\n\t\tClientSecret:          /* IDP's client secret */,\n\t\tKeyCacheExpiration:    time.Duration(/* Key expiration time */) * time.Second,\n\t\tClientCacheExpiration: time.Duration(/* Client info expiration */) * time.Second,\n\t\tCacheCleanupInterval:  time.Duration(/* Cache cleanup interval. Eg. 30 */) * time.Second,\n\t\tChallengeExpiration:   time.Duration(/* Challenge cookie expiration. Eg. 10 */) * time.Minutes,\n\t\tChallengeStore:        challengeCookieStore,\n\t})\n\n\t// Connects with Hydra and fills caches\n\terr = IDP.Connect(true /*TLS verification*/)\n\t// Return on error\n\n}\n\n```\n\n## Usage\n\n```go\n\nfunc HandleChallengeGET(w http.ResponseWriter, r *http.Request) {\n\t// 0. Render HTML page with a login form\n}\n\nfunc HandleChallengePOST(w http.ResponseWriter, r *http.Request) {\n\t// 0. Parse and validate login data (username:password, login cookie etc)\n\t//    Return on error\n\n\t// 1. Verify user's credentials (eg. check username:password).\n\t//    Return on error\n\t//    Obtain userid\n\n\t// 2. Create a Challenge\n\tchallenge, err := IDP.NewChallenge(r, userid)\n\t//    Return on error\n\n\t// 3. Save the Challenge to a cookie with a small TTL\n\terr = challenge.Save(w, r)\n\t//    Return on error\n\n\t// 4. Redirect to the consent endpoint\n}\n\n// Displays Consent screen. Here user agrees for listed scopes\nfunc HandleConsentGET(w http.ResponseWriter, r *http.Request) {\n\n\t// 0. Get the Challenge from the cookie\n\tchallenge, err := IDP.GetChallenge(r)\n\t//    Return on error\n\n\t// 1. Display consent screen\n\t//    Use challenge.User to get user's ID\n\t//    Use challenge.Scopes to display requested scopes\n\n\t// 2. If any error occured delete the Challenge cookie (optional)\n\tif err != nil {\n\t\terr = challenge.Delete(c.Writer, c.Request)\n\t}\n\n\t// 3. Render the HTML consent page\n}\n\nfunc HandleConsentPOST(w http.ResponseWriter, r *http.Request) {\n\t// 0. Get the Challenge from the cookie\n\tchallenge, err := IDP.GetChallenge(c.Request)\n\t//    Return on error\n\n\t// 1. Parse and validate consent data (eg. form answer=y or list of scopes)\n\t//    Return on error\n\n\t// 2. If user refused access\n\terr = challenge.RefuseAccess(w, r)\n\t//    Return\n\n\t// 3. If userf agreed to grant access\n\terr = challenge.GrantAccessToAll(w, r)\n\t//    Return\n}\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjanekolszak%2Fidp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjanekolszak%2Fidp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjanekolszak%2Fidp/lists"}