{"id":22211776,"url":"https://github.com/harborn-digital/secure-jwt-bundle","last_synced_at":"2025-09-16T04:42:35.315Z","repository":{"id":41286244,"uuid":"263580760","full_name":"Harborn-digital/secure-jwt-bundle","owner":"Harborn-digital","description":"Library that makes JWT more secure","archived":false,"fork":false,"pushed_at":"2023-12-06T15:21:56.000Z","size":341,"stargazers_count":5,"open_issues_count":10,"forks_count":10,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-04-04T00:41:35.913Z","etag":null,"topics":["managed","team-tbd"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":false,"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/Harborn-digital.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":"2020-05-13T09:12:23.000Z","updated_at":"2023-11-27T09:25:19.000Z","dependencies_parsed_at":"2024-12-02T20:49:34.403Z","dependency_job_id":null,"html_url":"https://github.com/Harborn-digital/secure-jwt-bundle","commit_stats":{"total_commits":94,"total_committers":8,"mean_commits":11.75,"dds":"0.42553191489361697","last_synced_commit":"e72d2fca0bb4f75e3dcef02112ead09189a02992"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/Harborn-digital/secure-jwt-bundle","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Harborn-digital%2Fsecure-jwt-bundle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Harborn-digital%2Fsecure-jwt-bundle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Harborn-digital%2Fsecure-jwt-bundle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Harborn-digital%2Fsecure-jwt-bundle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Harborn-digital","download_url":"https://codeload.github.com/Harborn-digital/secure-jwt-bundle/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Harborn-digital%2Fsecure-jwt-bundle/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":275364402,"owners_count":25451513,"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","status":"online","status_checked_at":"2025-09-16T02:00:10.229Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["managed","team-tbd"],"created_at":"2024-12-02T20:38:22.494Z","updated_at":"2025-09-16T04:42:35.293Z","avatar_url":"https://github.com/Harborn-digital.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Secure JWT Bundle\nSymfony bundle that makes JWT more secure\n\n## Install\nInstallation is not fluent and error free yet, but it is easy to work around:\n\n```bash\ncomposer require connectholland/secure-jwt-bundle\n```\n\nWill give error in post installation:\n\n```\nCannot autowire service \"ConnectHolland\\SecureJWTBundle\\EventSubscriber\\LoginSubscriber\": argument \"$googleAuthenticator\" of method \"__construct()\" references class \"Scheb\\TwoFactorBundle\\Security\\TwoFactor\\Provider\\Google\\GoogleAuthenticator\" but no such service exists.\n```\n\nConfigure scheb twofactor Google:\n\nIn the `scheb_two_factor.yaml` file:\n\n```yaml\nscheb_two_factor:\n    security_tokens:\n        - Symfony\\Component\\Security\\Core\\Authentication\\Token\\UsernamePasswordToken\n    google:\n        enabled: true\n        server_name: Secure Server\n        issuer: Connect Holland\n        digits: 6\n        window: 1\n```\n\nRun\n\n```bash\ncomposer require connectholland/secure-jwt-bundle\n```\n\nAgain to finish the installation. \n\nBTW1: Installation and configuration of the scheb twofactor bundle before installation of this bundle will also prevent this error.\u003cbr/\u003e \nBTW2: of course a PR that fixes these issues is welcome :)\n\n## Cookie storage\nTokens in local storage are insecure, so if you use tokens from a web interface you should store them somewhere else. A secure cookie is a good location. Configure cookie storage as follows:\n\n### Let the lexik/jwt-authentication-bundle look at cookies:\n\nIn the `lexik_jwt_authentication.yaml` config file:\n```yaml\nlexik_jwt_authentication:\n    secret_key: '%env(resolve:JWT_SECRET_KEY)%'\n    public_key: '%env(resolve:JWT_PUBLIC_KEY)%'\n    pass_phrase: '%env(JWT_PASSPHRASE)%'\n\n    token_extractors:\n            # Default header auth, can be useful to allow for other auth types (for example /api)\n            authorization_header:\n                enabled: true\n\n            # Make sure this is enabled\n            cookie:\n                enabled: true\n                name:    BEARER\n                set_cookies:\n                    BEARER: ~\n```\n\n### Make sure the token is set as a secure cookie\n\nIn the `security.yaml` config file:\n```yaml\n    login:\n        pattern:  ^/api/login\n        stateless: true\n        anonymous: true\n        json_login:\n            check_path:               /api/login_check\n            success_handler:          lexik_jwt_authentication.handler.authentication_success\n            failure_handler:          lexik_jwt_authentication.handler.authentication_failure\n```\n\n## Invalidate tokens\nBy default tokens are valid until they expire. This makes is impossible to really log out. You can configure token invalidatation to allow logouts:\n\n### Create database table\n\nIn the `doctrine.yaml` file:\n```yaml\ndoctrine:\n    orm:\n        mappings:\n            ConnectHolland\\SecureJWTBundle:\n                is_bundle: true\n                type: annotation\n                dir: '%kernel.project_dir%/vendor/connectholland/secure-jwt-bundle/src/Entity'\n                prefix: 'ConnectHolland\\SecureJWTBundle\\Entity'\n                alias: SecureJWTBundle\n```\n\nAnd run migrations:\n```bash\nbin/console doctrine:migrations:diff\nbin/console doctrine:migrations:migrate -n\n```\n\n### Configure API endpoint logout\n\nIn the `api_platform.yaml` file:\n\n```yaml\napi_platform:\n    mapping:\n        paths: ['%kernel.project_dir%/vendor/connectholland/secure-jwt-bundle/src/Message']\n```\n\nOf course do not remove other required paths that might already be in the `paths` configuration.\n\nThere will be a `logout` endpoint in your API. This endpoint requires a message formatted like:\n\n```json\n{\n  \"logout\": \"some string\"\n}\n```\n\nThe value of logout is not important and not used. This field is required because API platform requires at least one field in the message. (A better solution for this is welcome).\n\n### Do not allow invalidated tokens\n\nIn the `security.yaml` file:\n\n```yaml\n    api:\n        pattern: ^/api\n        stateless: true\n        anonymous: true\n        guard:\n            authenticators:\n                - ConnectHolland\\SecureJWTBundle\\Security\\Guard\\JWTTokenAuthenticator\n```\n\n## Two Factor Authentication in JWT\n\n### Configure Google Authenticator\n\nIn the `scheb_two_factor.yaml` file:\n\n```yaml\nscheb_two_factor:\n    security_tokens:\n        - Symfony\\Component\\Security\\Core\\Authentication\\Token\\UsernamePasswordToken\n    google:\n        enabled: true\n        server_name: Secure Server\n        issuer: Connect Holland\n        digits: 6\n        window: 1\n```\n\n### Use the two_factor_jwt security listener and provider\n\nIn the `security.yaml` file:\n\n```yaml\n    login:\n        pattern:  ^/api/login\n        stateless: true\n        anonymous: true        \n        two_factor_jwt:\n            check_path:               /api/login_check\n            success_handler:          ConnectHolland\\SecureJWTBundle\\Security\\Http\\Authentication\\AuthenticationSuccessHandler\n            failure_handler:          ConnectHolland\\SecureJWTBundle\\Security\\Http\\Authentication\\AuthenticationFailureHandler\n```\n\n### Implement the right interfaces\n\nYour User object should implement `ConnectHolland\\SecureJWTBundle\\Entity\\TwoFactorUserInterface`.\n\n## Using 2FA\n\n```bash\ncurl -X POST http://host/api/users/authenticate -H 'Content-Type: application/json' -d '{\"username\": \"username\", \"password\": \"password\"}'\n```\n\nThis will give the following response:\n```json\n{\n  \"result\":\"ok\",\n  \"status\":\"two factor authentication required\"\n}\n```\n\nIf 2FA is not yet setup you will receive:\n\n```json\n{\n  \"result\":\"ok\",\n  \"message\":\"use provided QR code to set up two factor authentication\",\n  \"qr\":\"QR code (data URL)\"\n}\n```\n\nIn the next call add the two factor challenge:\n\n```bash\ncurl -X POST http://host/api/users/authenticate -H 'Content-Type: application/json' -d '{\"username\": \"username\", \"password\": \"password\", \"challenge\": \"123456\"}'\n```\n\nIf correct you'll receive:\n\n```json\n{\n  \"result\":\"ok\"\n}\n```\n\nThe response headers will include a secure cookie containing the JWT token to allow future authenticated calls.\n\n## 2FA Remember this device\n\nThe remember device functionality allows users to skip the 2fa for a configurable amount of days. The default configuration is set to false, which means it doesn't set a REMEMBER_DEVICE cookie after logging in.\nThe default amount of days is set to 30.\n\nTo configure:\n\n\nIn the config/packages folder of the root project create a new file called:\n`connect_holland_secure_jwt.yaml`\n\nIn this file the configuration can be set:\n\n```yaml\nconnect_holland_secure_jwt:\n  is_remembered: true\n  expiry_days: 14\n```\n\nAs mentioned before, after logging in a REMEMBER_DEVICE cookie will be set. It will contain a unix expiry time and the email of the user.\n\nBesides placing the cookie it will be persisted in the: `secure_jwt_remember_device_token` table. This entity can be found in `src/Entity/RememberDeviceToken.php`\n\n## Recover codes\nYou can retrieve recovery codes for 2FA which allow you to reset 2FA. If a valid recovery code is entered as `challenge`, 2FA will be reset and you'll get a QR code response. \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fharborn-digital%2Fsecure-jwt-bundle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fharborn-digital%2Fsecure-jwt-bundle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fharborn-digital%2Fsecure-jwt-bundle/lists"}