{"id":37430825,"url":"https://github.com/andreacomo/tomcat-jwt-security","last_synced_at":"2026-01-16T06:35:02.860Z","repository":{"id":26754257,"uuid":"30212099","full_name":"andreacomo/tomcat-jwt-security","owner":"andreacomo","description":"Implements a security valve based on JWT token: generic HMAC, RSA and OpenID Connect","archived":false,"fork":false,"pushed_at":"2024-02-29T20:27:59.000Z","size":141,"stargazers_count":27,"open_issues_count":3,"forks_count":16,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-01-14T21:56:03.452Z","etag":null,"topics":["jwt","jwt-authentication","jwt-token","openidconnect-client","tomcat"],"latest_commit_sha":null,"homepage":"","language":"Java","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/andreacomo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","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,"zenodo":null}},"created_at":"2015-02-02T22:27:13.000Z","updated_at":"2023-11-27T07:24:33.000Z","dependencies_parsed_at":"2023-12-25T21:35:32.214Z","dependency_job_id":"e797f4e1-6b0a-4d53-9a87-932e3a06f094","html_url":"https://github.com/andreacomo/tomcat-jwt-security","commit_stats":null,"previous_names":["cosenonjaviste/tomcat-jwt-security"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/andreacomo/tomcat-jwt-security","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreacomo%2Ftomcat-jwt-security","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreacomo%2Ftomcat-jwt-security/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreacomo%2Ftomcat-jwt-security/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreacomo%2Ftomcat-jwt-security/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andreacomo","download_url":"https://codeload.github.com/andreacomo/tomcat-jwt-security/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreacomo%2Ftomcat-jwt-security/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28477878,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T06:30:42.265Z","status":"ssl_error","status_checked_at":"2026-01-16T06:30:16.248Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["jwt","jwt-authentication","jwt-token","openidconnect-client","tomcat"],"created_at":"2026-01-16T06:35:02.747Z","updated_at":"2026-01-16T06:35:02.807Z","avatar_url":"https://github.com/andreacomo.png","language":"Java","readme":"[![Build Status](https://travis-ci.org/andreacomo/tomcat-jwt-security.svg?branch=master)](https://travis-ci.org/andreacomo/tomcat-jwt-security)\n[![Released Version](https://img.shields.io/maven-central/v/it.cosenonjaviste/tomcat-jwt-security.svg)](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22it.cosenonjaviste%22%20a%3A%22tomcat-jwt-security%22)\n\n# tomcat-jwt-security\nThis project aims to bring JWT token authentication capabilities into **Tomcat 8**, implementing an authentication filter as a Tomcat Valve. JWT manipulation is based on [java-jwt](https://github.com/auth0/java-jwt) project.\n\nFor Tomcat 7, please use [version 1.1.0](https://github.com/andreacomo/tomcat-jwt-security/releases/tag/tomcat-jwt-security-1.1.0) or clone [tomcat-7 branch](https://github.com/andreacomo/tomcat-jwt-security/tree/tomcat-7).\n\nValve-based authentication is supposed to work along with Java **standard security constraints** placed in your *web.xml* file and will leave your server **stateless**: with a JWT token you can keep your Tomcat *free of http session*.\n\nFrom version 3.0.0, several improvements have been made (with *many breaking changes* - please refers to release notes).\nNow you can take advantages of signing and verifying your JWT tokens with:\n\n * **HMAC** algorithms, providing a **secret text** (the legacy approach, available since versions 2.x.x)\n * **RSA** algorithms, providing a **keystore with a public key** \n * **OpenID Connect** (OIDC) JWT ID Tokens are now validated against **public keys** downloaded from a valid JWKS uri, provided by your OIDC Identity Provider\n\n# Getting started\nYou can download artifacts (1.a) or build the project on your own (1.b), then configure Tomcat and your security constraints in your project to enable authentication system. \n\nFinally, read how to create tokens in your app, if you sign your tokens with HMAC or RSA.\n\n## 1.a Download artifacts\nDownload artifacts (project and dependencies), from Maven Central Repo, when using HMAC (`HmacJwtTokenValve`) or RSA (`RsaJwtTokenValve`) valves:\n* [tomcat-jwt-security-3.0.0.jar](https://repo1.maven.org/maven2/it/cosenonjaviste/tomcat-jwt-security/3.0.0/tomcat-jwt-security-3.0.0.jar)\n  * [java-jwt-3.9.0.jar](https://repo1.maven.org/maven2/com/auth0/java-jwt/3.9.0/java-jwt-3.9.0.jar)\n    * [jackson-databind-2.10.1.jar](https://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-databind/2.10.1/jackson-databind-2.10.1.jar) (this may *cause problems* with [some Tomcat version](https://stackoverflow.com/questions/23541532/org-apache-tomcat-util-bcel-classfile-classformatexception-invalid-byte-tag-in))\n      * [jackson-core-2.10.1.jar](https://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-core/2.10.1/jackson-core-2.10.1.jar)\n      * [jackson-annotations-2.10.1.jar](https://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-annotations/2.10.1/jackson-annotations-2.10.1.jar)\n    * [commons-codec-1.12.jar](https://repo1.maven.org/maven2/commons-codec/commons-codec/1.12/commons-codec-1.12.jar)\n    \nIf you need to use OpenID Connect valve (`OidcJwtTokenValve`), you need further dependencies:\n\n  * [jwks-rsa-0.9.0.jar](https://repo1.maven.org/maven2/com/auth0/jwks-rsa/0.9.0/jwks-rsa-0.9.0.jar)\n    * [guava-27.1-jre.jar](https://repo1.maven.org/maven2/com/google/guava/guava/27.1-jre/guava-27.1-jre.jar)\n      * [failureaccess-1.0.1.jar](https://repo1.maven.org/maven2/com/google/guava/failureaccess/1.0.1/failureaccess-1.0.1.jar)\n\nPlace dependencies into *TOMCAT_HOME/lib* directory\n\n## 1.b Build project\nYou can build with a simple\n```\nmvn install\n```\nand grab artifacts from *target/to-deploy* folder. Copy generated artifacts into *TOMCAT_HOME/lib* directory\n\n## 2. Register Valve\nNow it's time to register the valve. According to your signing method or token provider, from version 3.0.0 you can choose proper valve, according to your scenario:\n\n * `HmacJwtTokenValve`: to be used when tokens are signed with **HMAC**, based on a **pre-shared secret text**.\n   Configurable parameters are:\n     \n     | Parameter | Type | Mandatory | Default | Description |\n     | --- | --- | --- | --- | --- |\n     | `secret` | String | Y | | Passphrase used to verify the token sign. Since HMAC is a sync algorithm, it's also used to recreate and sign the token when `updateExpire` is `true` | \n     | `updateExpire` | Boolean | N | `false` | Each request produces a new token in `X-Auth` response header with a delayed expire time. This simulates default Servlet HTTP Session behaviour |\n     | `cookieName` | String | N | | Name of the cookie containing JWT token instead of HTTP headers |\n     | `customUserIdClaim` | String | N | `userId` | Claim that identify the user id |\n     | `customRolesClaim`| String | N | `roles` | Claim that identify user capabilities |\n     \n   Example \n   \n   ```xml\n   \u003cValve className=\"it.cosenonjaviste.security.jwt.valves.HmacJwtTokenValve\" \n         secret=\"my super secret password\"\n         updateExpire=\"true\"\n         cookieName=\"auth\" /\u003e\n   ```\n     \n * `RsaJwtTokenValve`: to be used when tokens are signed with **RSA**, based on certificates pairs.\n    Configurable parameters are:\n        \n      | Parameter | Type | Mandatory | Default | Description |\n      | --- | --- | --- | --- | --- |\n      | `keystorePath` | String | Y* | | Keystore file system path |\n      | `keystorePassword` | String | Y* | | Keystore password |\n      | `keyPairsAlias`| String | N | the first one in keystore | Keys pairs alias in keystore. If not provided, the first *public key* in keystore will be used |\n      | `keyStore` | Keystore | Y** | | Keystore instance (useful when keystore is in classpath and is java-based configured) |\n      | `cookieName` | String | N | | Name of the cookie containing JWT token instead of HTTP headers |\n      | `customUserIdClaim` | String | N | `userId` | Claim that identify the user id |\n      | `customRolesClaim`| String | N | `roles` | Claim that identify user capabilities |\n      \n      Mandatory groups (\\*) and (\\*\\*) are mutually exclusive: `keyStore` param *takes precedence*.\n        \n      Example \n      \n      ```xml\n      \u003cValve className=\"it.cosenonjaviste.security.jwt.valves.RsaJwtTokenValve\" \n                 keystorePath=\"/etc/keystores/keystore.jks\"\n                 keystorePassword=\"ks_password\"\n                 customUserIdClaim=\"sub\" \n                 customRolesClaim=\"authorities\" /\u003e\n      ```\n   \n * `OidcJwtTokenValve`: to be used when tokens are provided by an OpenID Connect Identity Provider (OIDC IDP).\n   Configurable parameters are:\n     \n     | Parameter | Type | Mandatory | Default | Description |\n     | --- | --- | --- | --- | --- |\n     | `issuerUrl` | URL | Y | | URL where to retrieve IDP keys: it's the value of `jwks_uri` key of `.well-known/openid-configuration` endpoint provided by your IDP  | \n     | `supportedAudiences` | String | N | | Allowed `aud` values in token. If `supportedAudiences` is not set, **no validation** is performed |\n     | `expiresIn` | Integer | N | 60 | Cache duration of keys before recontact IDP for new keys |\n     | `timeUnit` | TimeUnit | N | MINUTES | Cache time unit. Allowed values are: `NANOSECONDS`, `MICROSECONDS`, `MILLISECONDS`, `SECONDS`, `MINUTES`, `HOURS`, `DAYS` |\n     | `customUserIdClaim` | String | N | `sub` | Claim that identify the user id |\n     | `customRolesClaim`| String | N | `authorities` | Claim that identify user capabilities |\n     \n   Example \n   \n   ```xml\n   \u003cValve className=\"it.cosenonjaviste.security.jwt.valves.OidcJwtTokenValve\" \n             issuerUrl=\"http://idp.example.com/openid-connect/certs\"\n             expiresIn=\"30\"\n             timeUnit=\"MINUTES\" /\u003e\n   ```\n    \nValves can be configured in Tomcat in:\n* `server.xml` for registering valve at **Engine** or **Host** level\n* `context.xml` for registering valve at application **Context** level\n\nIn order for the valve to work, a **realm should be provided**. An example for a JDBCRealm can be found on [a post on TheJavaGeek](http://www.thejavageek.com/2013/07/07/configure-jdbcrealm-jaas-for-mysql-and-tomcat-7-with-form-based-authentication/)\n\n## 3. Enable `security-contraint`\nAll these valves check if requested url is under **security constraints**. So, valve behaviour will be activated only if your application *web.xml* file contains something like this:\n\n```xml\n\u003csecurity-constraint\u003e\n  \u003cweb-resource-collection\u003e\n\t\t\u003cweb-resource-name\u003eapi\u003c/web-resource-name\u003e\n\t\t\u003curl-pattern\u003e/api/*\u003c/url-pattern\u003e\n\t\u003c/web-resource-collection\u003e\n\t\u003cauth-constraint\u003e\n\t\t\u003crole-name\u003e*\u003c/role-name\u003e\n\t\u003c/auth-constraint\u003e\n\u003c/security-constraint\u003e\n\u003csecurity-role\u003e\n\t\u003crole-name\u003eadmin\u003c/role-name\u003e\n\u003c/security-role\u003e\n\u003csecurity-role\u003e\n\t\u003crole-name\u003edevop\u003c/role-name\u003e\n\u003c/security-role\u003e\n\u003clogin-config\u003e\n  \u003cauth-method\u003eBASIC\u003c/auth-method\u003e\n  \u003crealm-name\u003eMyAppRealm\u003c/realm-name\u003e\n\u003c/login-config\u003e\n```\nPlease note `\u003cauth-method\u003e` tag: is set to **BASIC** in order to *avoid HTTP Session creation on server side*. If you omit `\u003cauth-method\u003e` or use another authentication method, Tomcat will create an HTTP session for you, but we *want our server stateless*!\n\nNow your server is ready. How to generate a token from your app?\n\n# How to integrate in your project\n\n## HMAC and RSA\n`HmacJwtTokenValve` and `RsaJwtTokenValve` inherits from an abstract `JwtTokenValve` that is supposed to search for authentication token according to these priorities:\n * in `X-Auth` *header param* \n * in `Authorization` *header param* with token preceded by `Bearer ` type \n * in `access_token` *query parameter* (useful for downloading a file for example)\n * in a `cookie`: cookie's name is set by valve parameter *cookieName*\n\nYour login controller **must** create a token in order to be validated: *each following request* to protected application must contain one of the authentication methods above.\n\nYou can use classes provided by *[java-jwt project](https://github.com/auth0/java-jwt)* (recommended), for example:\n\n```java\nString token = JWT.create()\n       .withSubject(securityContext.getUserPrincipal().getName())\n       .withArrayClaim(\"authorities\", new String[]{\"admin\", \"devop\"})\n       .withIssuedAt(new Date())\n       .sign(Algorithm.HMAC256(\"my super secret password\"));\n\n...\n\nresponse.addHeader(JwtConstants.AUTH_HEADER, token);\n\n```\n\nor our utility classes such as `JwtTokenBuilder` or `JwtConstants` (legacy): *tomcat-jwt-security* is also available on Maven Central. \nYou can include it in your project as **provided** dependency (because is in your TOMCAT_HOME/lib folder already!):\n\n```xml\n\u003cdependency\u003e\n\t\u003cgroupId\u003eit.cosenonjaviste\u003c/groupId\u003e\n\t\u003cartifactId\u003etomcat-jwt-security\u003c/artifactId\u003e\n\t\u003cversion\u003e3.0.0\u003c/version\u003e\n\t\u003cscope\u003eprovided\u003c/scope\u003e\n\u003c/dependency\u003e\n```\n\nAnd use it like this in your *login controller*:\n```java\nString token = JwtTokenBuilder.create(Algorithm.HMAC256(\"my super secret password\"))\n                            .userId(securityContext.getUserPrincipal().getName())\n                            .roles(Arrays.asList(\"admin\", \"devop\"))\n                            .expirySecs(1800)\n                            .build();\n\n...\n\nresponse.addHeader(JwtConstants.AUTH_HEADER, token);\n```\n\n## OpenID Connect\nIn case of `OidcJwtTokenValve`, you *don't need a login controller*, since you are just protecting your APIs as [OAuth2 Resource Server](https://www.oauth.com/oauth2-servers/the-resource-server/). \nAuthentication is handled elsewhere to gather the JWT: just configure the valve and send obtained JWT token in every HTTP header `Authorization`, preceded by `Bearer`.\n\nEnjoy now your stateless security system on Tomcat!!\n\n# JWT Valve and Spring Boot\nIf you want to use this Valve with **Embedded Tomcat** provided by *Spring Boot*, forget about `web.xml` or `context.xml`!\nJust include as **Maven dependency** in `compile` scope and implement a `EmbeddedServletContainerCustomizer` like this:\n\n```java\n@Configuration\npublic class TomcatJwtSecurityConfig implements EmbeddedServletContainerCustomizer {\n\n    @Override\n    public void customize(ConfigurableEmbeddedServletContainer container) {\n        if (container instanceof TomcatEmbeddedServletContainerFactory) {\n            TomcatEmbeddedServletContainerFactory factory = (TomcatEmbeddedServletContainerFactory) container;\n            factory.addContextValves(newJwtTokenValve());\n            factory.addContextValves(new BasicAuthenticator());\n            factory.addContextCustomizers(context -\u003e {\n                context.setRealm(newJdbcRealm());\n\n                // replace web.xml entries\n                context.addConstraint(unsecured());\n                context.addConstraint(secured());\n                context.addSecurityRole(\"admin\");\n                context.addSecurityRole(\"devop\");\n            });\n        }\n    }\n\n    private SecurityConstraint unsecured() {\n        SecurityCollection collection = new SecurityCollection(\"login\", \"login\");\n        collection.addPattern(\"/api/login\");\n\n        SecurityConstraint securityConstraint = new SecurityConstraint();\n        securityConstraint.addCollection(collection);\n\n        return securityConstraint;\n    }\n\n    private SecurityConstraint secured() {\n        SecurityCollection collection = new SecurityCollection(\"api\", \"api\");\n        collection.addPattern(\"/api/*\");\n\n        SecurityConstraint securityConstraint = new SecurityConstraint();\n        securityConstraint.addAuthRole(\"*\");\n        securityConstraint.setAuthConstraint(true);\n        securityConstraint.addCollection(collection);\n\n        return securityConstraint;\n    }\n\n    private HmacJwtProvider newJwtTokenValve() {\n        HmacJwtProvider valve = new HmacJwtProvider();\n        valve.setSecret(\"my-secret\");\n        valve.setUpdateExpire(true);\n        return valve;\n    }\n    \n    private Realm newJdbcRealm() {\n        // your favourite realm \n    }\n}\n```\n\nSome notes:\n* this is a programmatic version of `web.xml` configuration (and `context.xml`)\n* `BasicAuthenticator` is required because `JwtTokenValve` **is not an authenticator**: \n`BasicAuthenticator` mainly delegates login phase to registered Realm in *Tomcat Context*.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandreacomo%2Ftomcat-jwt-security","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandreacomo%2Ftomcat-jwt-security","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandreacomo%2Ftomcat-jwt-security/lists"}