{"id":16750125,"url":"https://github.com/alexferl/echo-boilerplate","last_synced_at":"2026-01-12T00:46:18.637Z","repository":{"id":43596602,"uuid":"161701098","full_name":"alexferl/echo-boilerplate","owner":"alexferl","description":"Boilerplate for the Echo framework with authentication, authorization and request/response validation.","archived":false,"fork":false,"pushed_at":"2024-04-07T22:53:38.000Z","size":10767,"stargazers_count":44,"open_issues_count":0,"forks_count":16,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-18T05:51:11.099Z","etag":null,"topics":["12-factor","boilerplate","boilerplate-application","casbin","echo","echo-boilerplate","echo-casbin","echo-framework","echo-golang","echo-jwt","go","golang","jwt","labstack-echo","openapi","openapi3"],"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/alexferl.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":"2018-12-13T22:16:36.000Z","updated_at":"2025-03-05T12:00:22.000Z","dependencies_parsed_at":"2024-01-26T01:29:30.721Z","dependency_job_id":"09e8cdbb-4ee5-4f4c-920f-20d27a6c407e","html_url":"https://github.com/alexferl/echo-boilerplate","commit_stats":null,"previous_names":["admiralobvious/echo-boilerplate"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexferl%2Fecho-boilerplate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexferl%2Fecho-boilerplate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexferl%2Fecho-boilerplate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexferl%2Fecho-boilerplate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alexferl","download_url":"https://codeload.github.com/alexferl/echo-boilerplate/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244880409,"owners_count":20525507,"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":["12-factor","boilerplate","boilerplate-application","casbin","echo","echo-boilerplate","echo-casbin","echo-framework","echo-golang","echo-jwt","go","golang","jwt","labstack-echo","openapi","openapi3"],"created_at":"2024-10-13T02:27:09.665Z","updated_at":"2026-01-12T00:46:18.587Z","avatar_url":"https://github.com/alexferl.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# echo-boilerplate [![Go Report Card](https://goreportcard.com/badge/github.com/alexferl/echo-boilerplate)](https://goreportcard.com/report/github.com/alexferl/echo-boilerplate) [![codecov](https://codecov.io/gh/alexferl/echo-boilerplate/branch/master/graph/badge.svg)](https://codecov.io/gh/alexferl/echo-boilerplate)\n\nA Go 1.22+ boilerplate app using the minimalist [echo](https://github.com/labstack/echo) framework and with\nauthentication, authorization and request/response validation.\n\n\u003e **Note**: I use this as a starting point for personal projects, it can and will change without notice.\n\n## Features\n- [JWT](https://jwt.io/) for authentication with access and [refresh](https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/) tokens.\n The access token can be sent in the [Authorization](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization) header or\n as a [cookie](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies). See [echo-jwt](https://github.com/alexferl/echo-jwt).\n- [Casbin](https://casbin.io/) for authorization using RBAC. See [echo-casbin](https://github.com/alexferl/echo-casbin).\n- [OpenAPI](https://www.openapis.org/) for request and response validation. See [echo-openapi](https://github.com/alexferl/echo-openapi).\n\n## Requirements\nBefore getting started, install the following:\n\nRequired:\n- [pre-commit](https://pre-commit.com/#install)\n- [MongoDB](https://www.mongodb.com/docs/manual/installation/#mongodb-installation-tutorials)\n\nOptional:\n\n- [gofumpt](https://pkg.go.dev/mvdan.cc/gofumpt) (needed to run `make fmt`)\n- [redocly-cli](https://redocly.com/docs/cli/installation/) (needed to run `make openapi-lint`)\n\n## Using\nSetup the dev environment first:\n```shell\nmake dev\n```\n\u003e**Note**: An RSA private key will be generated in the current folder to sign and verify the JSON web tokens.\n\n### Creating the superuser\nLaunch the superuser cmd with `go run ./cmd/superuser --password \u003cyour password\u003e`. You can change the default values\nwith the following flags: `--email`, `--name` and `--username`. You can view all the other settings with `--help`.\n\n### Building \u0026 Running locally\n```shell\nmake run\n```\n### Using the API\n#### Login\nRequest:\n```shell\ncurl --request POST \\\n  --url http://localhost:1323/auth/login \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n\t\"email\": \"super@example.com\",\n\t\"password\": \"\u003cyour password\u003e\"\n}'\n```\nResponse:\n```json\n{\n  \"access_token\": \"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...\",\n  \"expires_in\": 3600,\n  \"refresh_token\": \"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...\",\n  \"token_type\": \"Bearer\"\n}\n```\n**Note**: The `access_token` only lasts 60 minutes by default, this is as designed. A client\n(like an [SPA](https://en.wikipedia.org/wiki/Single-page_application) or a mobile application) would have an interceptor\nto catch the 401 responses, send the `refresh_token` to the `/auth/refresh` endpoint to get new access and refresh tokens and\nthen retry the previous request with the new `access_token` which should then succeed. The duration of the `access_token`\ncan be modified with `--jwt-access-token-expiry` and the `refresh_token` with `--jwt-refresh-token-expiry`.\n\n#### Get currently authenticated user\nRequest:\n\nUsing the `Authorization` header:\n```shell\ncurl --request GET \\\n  --url http://localhost:1323/me \\\n  --header 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...'\n```\n\nUsing the cookie (the cookie is sent automatically with web browsers, HTTPie and some other clients):\n```shell\ncurl --request GET \\\n  --url http://localhost:1323/me \\\n  --cookie access_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...\n```\n\nResponse:\n```json\n{\n  \"id\": \"cdhgh0dfclscplnrcuag\",\n  \"username\": \"super\",\n  \"email\": \"super@example.com\",\n  \"name\": \"Super\",\n  \"bio\": \"\",\n  \"created_at\": \"2022-11-03T00:17:05.837Z\",\n  \"updated_at\": null\n}\n```\n\n### OpenAPI docs\nYou can see the OpenAPI docs by running the app and navigating to `http://localhost:1323/docs` or by\nopening [assets/index.html](docs/index.html) in your web browser.\n\n### Repository layout\n```\n.\n├── casbin    \u003c--- model and policy files for Casbin\n├── cmd       \u003c--- entrypoints\n├── config    \u003c--- config structs and defaults are specified here\n├── configs   \u003c--- config files, for configs that rarely change, but should override the defaults\n├── data      \u003c--- base mapper, database helpers\n├── docs      \u003c--- generated documentation from OpenAPI schema\n├── handlers  \u003c--- HTTP handlers (aka controllers, endpoints etc.) that interacts with the services\n├── mappers   \u003c--- mapper layer that the services use to insert/retrieve models from the database\n├── models    \u003c--- structs defining the various resources\n├── openapi   \u003c--- OpenAPI schema files\n├── server    \u003c--- glues handlers/services/mappers\n├── services  \u003c--- service layer that interacts with the mappers\n├── testing   \u003c--- testing helpers\n└── util      \u003c--- general helpers\n```\n\n### Usage\n```shell\ngo run ./cmd/server --help\n```\n\n```\nUsage of ./echo-boilerplate:\n      --app-name string                                The name of the application. (default \"app\")\n      --base-url string                                Base URL where the app will be served (default \"http://localhost:1323\")\n      --casbin-model string                            Casbin model file (default \"./casbin/model.conf\")\n      --casbin-policy string                           Casbin policy file (default \"./casbin/policy.csv\")\n      --cookies-domain string                          Cookies domain\n      --cookies-enabled                                Send cookies with authentication requests\n      --csrf-cookie-domain string                      CSRF cookie domain\n      --csrf-cookie-name string                        CSRF cookie name (default \"csrf_token\")\n      --csrf-enabled                                   CSRF enabled\n      --csrf-header-name string                        CSRF header name (default \"X-CSRF-Token\")\n      --csrf-secret-key string                         CSRF secret used to hash the token\n      --env-name string                                The environment of the application. Used to load the right configs file. (default \"local\")\n      --http-bind-address ip                           The IP address to listen at. (default 127.0.0.1)\n      --http-bind-port uint                            The port to listen at. (default 1323)\n      --http-cors-allow-credentials                    Tells browsers whether to expose the response to frontend JavaScript code when the request's credentials mode (Request.credentials) is 'include'.\n      --http-cors-allow-headers strings                Indicate which HTTP headers can be used during an actual request.\n      --http-cors-allow-methods strings                Indicates which HTTP methods are allowed for cross-origin requests. (default [GET,HEAD,PUT,PATCH,POST,DELETE])\n      --http-cors-allow-origins strings                Indicates whether the response can be shared with requesting code from the given origin. (default [*])\n      --http-cors-enabled                              Enable cross-origin resource sharing.\n      --http-cors-expose-headers strings               Indicates which headers can be exposed as part of the response by listing their name.\n      --http-cors-max-age int                          Indicates how long the results of a preflight request can be cached.\n      --http-graceful-timeout duration                 Timeout for graceful shutdown. (default 30s)\n      --http-log-requests                              Controls the logging of HTTP requests (default true)\n      --http-tls-cert-file string                      TLS certificate file\n      --http-tls-key-file string                       TLS key file\n      --jwt-access-token-cookie-name string            JWT access token cookie name (default \"access_token\")\n      --jwt-access-token-expiry duration               JWT access token expiry (default 1h0m0s)\n      --jwt-issuer string                              JWT issuer (default \"http://localhost:1323\")\n      --jwt-private-key string                         JWT private key file path (default \"./private-key.pem\")\n      --jwt-refresh-token-cookie-name string           JWT refresh token cookie name (default \"refresh_token\")\n      --jwt-refresh-token-expiry duration              JWT refresh token expiry (default 720h0m0s)\n      --log-level string                               The granularity of log outputs. Valid levels: 'PANIC', 'FATAL', 'ERROR', 'WARN', 'INFO', 'DEBUG', 'TRACE', 'DISABLED' (default \"INFO\")\n      --log-output string                              The output to write to. 'stdout' means log to stdout, 'stderr' means log to stderr. (default \"stdout\")\n      --log-writer string                              The log writer. Valid writers are: 'console' and 'json'. (default \"console\")\n      --mongodb-app-name string                        MongoDB app name\n      --mongodb-connect-timeout-ms duration            MongoDB connect timeout ms (default 10s)\n      --mongodb-password string                        MongoDB password\n      --mongodb-replica-set string                     MongoDB replica set\n      --mongodb-server-selection-timeout-ms duration   MongoDB server selection timeout ms (default 10s)\n      --mongodb-socket-timeout-ms duration             MongoDB socket timeout ms (default 30s)\n      --mongodb-uri string                             MongoDB URI (default \"mongodb://localhost:27017\")\n      --mongodb-username string                        MongoDB username\n      --oauth2-google-client-id string                 OAuth2 Google client id\n      --oauth2-google-client-secret string             OAuth2 Google client secret\n      --oauth2-providers strings                       OAuth2 providers\n      --openapi-schema string                          OpenAPI schema file (default \"./openapi/openapi.yaml\")\n```\n\n### Docker\n#### Build\n```shell\nmake docker-build\n```\n\n#### Run\n```shell\nmake docker-run\n```\n\n#### Passing args\nCLI:\n```shell\ndocker run -p 1323:1323 --rm echo-boilerplate --env-name prod\n```\n\nEnvironment variables:\n```shell\ndocker run -p 1323:1323 -e \"APP_ENV_NAME=prod\" --rm echo-boilerplate\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexferl%2Fecho-boilerplate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falexferl%2Fecho-boilerplate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexferl%2Fecho-boilerplate/lists"}