{"id":27430117,"url":"https://github.com/gravitytwog/go-jwt-auth","last_synced_at":"2025-04-14T14:32:14.170Z","repository":{"id":245580937,"uuid":"818573431","full_name":"GravityTwoG/go-jwt-auth","owner":"GravityTwoG","description":"Example of authorization with access + refresh token pair. https://jwt-auth.abazbekov.ru, https://jwt-auth-api.abazbekov.ru You can use this api to test your applications running on origin: localhost:5173","archived":false,"fork":false,"pushed_at":"2024-12-08T13:53:20.000Z","size":153,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-12-08T14:32:56.669Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://jwt-auth-api.abazbekov.ru","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/GravityTwoG.png","metadata":{"files":{"readme":"README.MD","changelog":null,"contributing":null,"funding":null,"license":null,"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-06-22T08:02:36.000Z","updated_at":"2024-12-08T13:53:24.000Z","dependencies_parsed_at":"2024-07-16T10:06:22.327Z","dependency_job_id":"b774186e-1a18-47ff-81c9-41bab79ea822","html_url":"https://github.com/GravityTwoG/go-jwt-auth","commit_stats":null,"previous_names":["gravitytwog/go-jwt-auth"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GravityTwoG%2Fgo-jwt-auth","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GravityTwoG%2Fgo-jwt-auth/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GravityTwoG%2Fgo-jwt-auth/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GravityTwoG%2Fgo-jwt-auth/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GravityTwoG","download_url":"https://codeload.github.com/GravityTwoG/go-jwt-auth/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248897135,"owners_count":21179544,"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":"2025-04-14T14:31:27.433Z","updated_at":"2025-04-14T14:32:14.151Z","avatar_url":"https://github.com/GravityTwoG.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JWT authorization example on golang\n\nRun whole system using command: `make infra`\n\nSwagger docs located by url: https://jwt-auth-api.abazbekov.ru/swagger/index.html\n\n## Frontend\n\n- https://github.com/GravityTwoG/react-jwt-auth\n\n## Flow\n\n### Authentication Flow\n\nClient makes POST response with:\n\n```typescript\nbody: {\n  email: string;\n  password: string;\n  fingerprint: string; (browser, device fingerprint or some persistent id stored on device)\n}\n```\n\nServer checks login credentials.\nServer creates pair of accessToken and refreshToken. Server saves refreshToken in persistent storage and responds with:\n\n```typescript\nbody: {\n  accessToken: string;\n  refreshToken: string; (for those clients, who doesn't support cookies)\n}\nheader: Set-Cookie: refreshToken=\u003ctoken\u003e, Domain, Path ...\n```\n\nClient should store either only the accessToken or both the accessToken and refreshToken.\n\n```mermaid\nsequenceDiagram\n    participant Client\n    participant Server\n    participant Storage\n    Client-\u003e\u003eServer: POST /login {email, password, fingerprint}\n    Server-\u003e\u003eStorage: Save refreshToken\n    Storage--\u003e\u003eServer: Confirmation\n    Server--\u003e\u003eClient: 200 OK {accessToken, refreshToken}\n    Server--\u003e\u003eClient: Set-Cookie: refreshToken=\u003ctoken\u003e\n```\n\n### Authorization Flow\n\nClient must pass header Authorization: Bearer \u003ctoken\u003e in each request that should be authorized.\n\n```typescript\nheader Authorization: Bearer\u003ctoken\u003e;\n```\n\nServer checks this token without accessing the database or any other storage:\n\n- If token is valid, the request is passed to the endpoint handler.\n- If token is not valid, the server responds with HTTP 401 Unauthorized.\n\n```mermaid\nsequenceDiagram\n    participant Client\n    participant Server\n    Client-\u003e\u003eServer: Request with Authorization: Bearer \u003ctoken\u003e\n    alt Token is valid\n        Server-\u003e\u003eServer: Process request\n        Server--\u003e\u003eClient: 200 OK with response\n    else Token is invalid\n        Server--\u003e\u003eClient: 401 Unauthorized\n    end\n```\n\n### Refresh Tokens Flow\n\nClient makes POST request with:\n\n```typescript\nbody: {\n  fingerprint: string;\n}\nheader Cookie: refreshToken=abc ...\n```\n\nServer checks refreshToken.\nServer checks for the presence of the refreshToken in persistent storage.\nIf refreshToken not found in storage, then server deletes all refreshTokens of current user from storage. (The refreshToken may have been stolen)\n\nServer compares the userAgent of the request and the passed fingerprint with the stored userAgent and fingerprint. If they are not equal, then the server deletes all refreshTokens of the current user.\n\nIn other cases:\nServer creates a pair of accessToken and refreshToken. Server updates the refreshToken in persistent storage and responds with:\n\n```typescript\nbody: {\n  accessToken: string;\n  refreshToken: string; (for those clients, who doesn't support cookies)\n}\nheader: Set-Cookie: refreshToken=\u003ctoken\u003e, Domain, Path ...\n```\n\n```mermaid\nsequenceDiagram\n    participant Client\n    participant Server\n    participant Storage\n    Client-\u003e\u003eServer: POST /refresh {fingerprint} + Cookie: refreshToken\n    Server-\u003e\u003eStorage: Check refreshToken\n    alt refreshToken not found\n        Server-\u003e\u003eStorage: Delete all user's refreshTokens\n        Server--\u003e\u003eClient: 401 Unauthorized\n    else refreshToken found\n        Server-\u003e\u003eServer: Compare userAgent \u0026 fingerprint\n        alt userAgent or fingerprint mismatch\n            Server-\u003e\u003eStorage: Delete all user's refreshTokens\n            Server--\u003e\u003eClient: 401 Unauthorized\n        else userAgent and fingerprint match\n            Server-\u003e\u003eStorage: Update refreshToken\n            Storage--\u003e\u003eServer: Confirmation\n            Server--\u003e\u003eClient: 200 OK {accessToken, refreshToken}\n            Server--\u003e\u003eClient: Set-Cookie: refreshToken=\u003cnew-token\u003e\n        end\n    end\n```\n\n### Logout Flow\n\nClient makes POST request with:\n\n```typescript\nheader Cookie: refreshToken=abc ...\nheader Authorization: Bearer \u003ctoken\u003e\n```\n\nServer authorizes request.\nServer checks presence of cookie with refreshToken and:\n\n- if there is no refreshToken, then server responds with HTTP 200 OK\n- if there is refreshToken, then server deletes refreshToken from its storage and responds with HTTP 200 OK.\n\nIn both cases server also resets refreshToken cookie.\n\n```mermaid\nsequenceDiagram\n    participant Client\n    participant Server\n    participant Storage\n    Client-\u003e\u003eServer: POST /logout + Authorization + Cookie: refreshToken\n    Server-\u003e\u003eServer: Authorize request\n    alt No refreshToken in cookie\n        Server--\u003e\u003eClient: 200 OK\n    else refreshToken in cookie\n        Server-\u003e\u003eStorage: Delete refreshToken\n        Storage--\u003e\u003eServer: Confirmation\n        Server--\u003e\u003eClient: 200 OK\n    end\n    Server--\u003e\u003eClient: Reset refreshToken cookie\n```\n\n### Logout All Flow\n\nClient makes POST request with:\n\n```typescript\nheader Cookie: refreshToken=abc ...\nheader Authorization: Bearer \u003ctoken\u003e\n```\n\nServer authorizes request.\nServer checks presence of cookie with refreshToken and:\n\n- if there is no refreshToken, then server responds with HTTP 401 Unauthorized\n- if there is refreshToken, then server deletes all refreshTokens of current user and responds with HTTP 200 OK. Server also resets refreshToken cookie.\n\n```mermaid\nsequenceDiagram\n    participant Client\n    participant Server\n    participant Storage\n    Client-\u003e\u003eServer: POST /logout-all + Authorization + Cookie: refreshToken\n    Server-\u003e\u003eServer: Authorize request\n    alt No refreshToken in cookie\n        Server--\u003e\u003eClient: 401 Unauthorized\n    else refreshToken in cookie\n        Server-\u003e\u003eStorage: Delete all user's refreshTokens\n        Storage--\u003e\u003eServer: Confirmation\n        Server--\u003e\u003eClient: 200 OK\n        Server--\u003e\u003eClient: Reset refreshToken cookie\n    end\n```\n\n## Development\n\n### Prerequisites\n\n```sh\n# install golangci-lint\ncurl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.59.1\n```\n\n### Generate RSA keys (you can do this using OpenSSL):\n\n```sh\nopenssl genrsa -out private.pem 2048\nopenssl rsa -in private.pem -pubout -out public.pem\n```\n\nEncode the PEM files as Base64:\n\n```sh\nexport JWT_PRIVATE_KEY=$(cat private.pem | base64 -w 0)\n```\n\n### Folder structure\n\n- cmd - entry files for rest-api and migrator\n- internal - internal packages\n- - rest-api\n- - - config - load config from .env\n- - - database - db context\n- - - models - database models\n- - - repositories - data access layer\n- - - entities - domain specific\n- - - services - domain specific services\n- - - controllers - REST controllers\n- - - dto - Data transfer objects\n- deployments - docker and docker compose files\n- docs - swagger docs\n\n```\n\n```\n\n```\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgravitytwog%2Fgo-jwt-auth","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgravitytwog%2Fgo-jwt-auth","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgravitytwog%2Fgo-jwt-auth/lists"}