{"id":26676962,"url":"https://github.com/theskyinflames/oauth2-example","last_synced_at":"2025-03-26T04:17:37.934Z","repository":{"id":283778148,"uuid":"802113503","full_name":"theskyinflames/oauth2-example","owner":"theskyinflames","description":"This is a simple example of protecting REST endpoints with OAuth2 IAM","archived":false,"fork":false,"pushed_at":"2024-05-25T05:26:30.000Z","size":4522,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-22T05:33:03.212Z","etag":null,"topics":["doker","go","golang","jose-jwt","jwks","jwt","jwt-authentication","jwt-token","oauth2","oauth2-cl","oauth2-client","openid","openid-connect","rsa-key-pair"],"latest_commit_sha":null,"homepage":"","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/theskyinflames.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":"2024-05-17T14:52:30.000Z","updated_at":"2024-05-25T05:25:57.000Z","dependencies_parsed_at":"2025-03-22T05:33:05.776Z","dependency_job_id":"b276f08f-db91-41c4-8fb8-5c040dbe5eba","html_url":"https://github.com/theskyinflames/oauth2-example","commit_stats":null,"previous_names":["theskyinflames/oauth2-example"],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theskyinflames%2Foauth2-example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theskyinflames%2Foauth2-example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theskyinflames%2Foauth2-example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theskyinflames%2Foauth2-example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/theskyinflames","download_url":"https://codeload.github.com/theskyinflames/oauth2-example/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245585807,"owners_count":20639671,"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":["doker","go","golang","jose-jwt","jwks","jwt","jwt-authentication","jwt-token","oauth2","oauth2-cl","oauth2-client","openid","openid-connect","rsa-key-pair"],"created_at":"2025-03-26T04:17:37.380Z","updated_at":"2025-03-26T04:17:37.926Z","avatar_url":"https://github.com/theskyinflames.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# oauth2-example\n\nThis is a simple example of protecting REST endpoints using an identity manager and OpenID as authentication protocol. As identity manager, I use [Keycloak](https://www.keycloak.org)\n\n## **Enjoy!!!!**\n\n## How to run it\n\n1. Start the identity manager and the API:\n\n```sh\n    make run\n```\n\n2. Open the browser and go to [protected endpoint](http://localhost:9000/protected)\n\nWhen you do it, you'll be redirected to the log in page of the identy manager. Then log in and you'll be redirected to protected endpoint with a valid authentication JWT token.\n\nUser credentials to log in:\n\n- user: jarus\n- password: jarus\n\n**That's it !!! :-D**\n\n## What authentication middleware does\n\nThe `http.AuthMiddleware` function in the provided code is a middleware function in Go that is used to check if a user is authenticated before allowing them to access certain routes or resources. Let's break down how it works:\n\n1. The `AuthMiddleware` function takes in a slice of `*rsa.PublicKey` as a parameter. This is used to verify and parse the JSON Web Tokens (JWT) received from the user.\n\n2. Inside the `AuthMiddleware` function, it returns another function of type `echo.MiddlewareFunc`. This inner function is the actual middleware that will be executed for each request.\n\n3. The inner middleware function takes in a `next` handler function of type `echo.HandlerFunc` and returns another `echo.HandlerFunc`. This allows the middleware to wrap around the subsequent handler functions in the request chain.\n\n4. Within the inner middleware function, it first checks if the current request path is either \"/login\" or \"/callback\". If it is, it skips the authentication check and proceeds to the next handler by calling `next(c)`.\n\n5. If the request path is not \"/login\" or \"/callback\", it proceeds to check for the authentication token in the request cookie. It uses the `c.Cookie(authCookieName)` function to retrieve the cookie with the name \"my-auth-cookie\".\n\n6. If there is an error retrieving the cookie or if the token value is empty, it logs an error and redirects the user to the \"/login\" page using `c.Redirect(http.StatusTemporaryRedirect, \"/login\")`.\n\n7. If the token is successfully retrieved from the cookie, it then calls the `parseJWT` function (which is not shown in the provided code) to parse and validate the token using the provided `rsaPublicKey`. If there is an error parsing the token, it logs an error and redirects the user to the \"/login\" page.\n\n8. If the token is successfully parsed, it extracts the roles from the token and sets them in the request context using `c.Set(\"roles\", roles)`.\n\n9. Finally, it calls the `next(c)` function to proceed to the next handler in the request chain.\n\nIn summary, the `AuthMiddleware` function is a middleware that checks if a user is authenticated by verifying the JWT token stored in a cookie. It ensures that only authenticated users with valid tokens and the required roles can access protected routes or resources.\n\n# Authentication process diagram\n\n```mermaid\nsequenceDiagram\n    participant User\n    participant WebBrowser as Web Browser\n    participant API as Go API\n    participant IAM as IAM Manager\n\n    alt Cookie not present or is invalid\n        User-\u003e\u003eWebBrowser: Access /protected\n        WebBrowser-\u003e\u003eAPI: GET /protected\n        API-\u003e\u003eWebBrowser: Redirect to /login\n        WebBrowser-\u003e\u003eAPI: GET /login\n        API-\u003e\u003eWebBrowser: Redirect to OAuth Login URL\n        WebBrowser-\u003e\u003eIAM: Login request\n        IAM-\u003e\u003eUser: Display login page\n        User-\u003e\u003eWebBrowser: Provide credentials\n        WebBrowser-\u003e\u003eIAM: Send authentication request\n        IAM--\u003e\u003eWebBrowser: Authentication response\n        WebBrowser-\u003e\u003eAPI: GET /callback with code\n        API-\u003e\u003eIAM: Exchange code for token\n        IAM--\u003e\u003eAPI: Token response\n        API-\u003e\u003eWebBrowser: Set cookie and redirect to /protected\n        WebBrowser-\u003e\u003eAPI: GET /protected with cookie\n        API-\u003e\u003eWebBrowser: Serve protected content\n    else Cookie present and valid\n        User-\u003e\u003eWebBrowser: Access /protected with valid cookie\n        WebBrowser-\u003e\u003eAPI: GET /protected\n        API-\u003e\u003eWebBrowser: Serve protected content\n    end\n```\n\n## Pending\n\n- Adding logout handler\n\n## Used stack\n\n- Go 1.22.3\n- Keycloack 24.0.1\n- Docker 25.0.3\n- Google Chrome as browser\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftheskyinflames%2Foauth2-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftheskyinflames%2Foauth2-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftheskyinflames%2Foauth2-example/lists"}