{"id":20508,"date":"2016-06-08T10:00:36","date_gmt":"2016-06-08T17:00:36","guid":{"rendered":"https:\/\/www.jamasoftware.com\/?p=20508"},"modified":"2023-01-12T16:55:34","modified_gmt":"2023-01-13T00:55:34","slug":"spring-security-oauth-multi-tenant","status":"publish","type":"post","link":"https:\/\/www.jamasoftware.com\/legacy\/blog\/2016\/06\/08\/spring-security-oauth-multi-tenant\/","title":{"rendered":"Extending Spring Security OAuth for Multi-Tenant"},"content":{"rendered":"<p>In being a SaaS company, we are gradually chipping away at our good old monolith, turning pieces into micro-services that can scale horizontally, and that scale efficiently by use of multi-tenancy. A single micro-service can have multiple instances, and each instance serves a multitude of customers. Multi-tenancy has implications on application state, and a common pattern is for database tables to be shared across tenants, where each record links to a specific tenant. It also requires some lifting to make sure that the application always understands which tenant it is working for.<\/p>\n<p>We are a Spring shop, and happy users of Spring Boot for our micro-services. We recently built the &#8220;Jama OAuth service&#8221;, which is an OAuth 2 compatible authorization server, that essentially issues access tokens to clients of our system (given their credentials). It implements OAuth&#8217;s so-called &#8220;client credentials&#8221; flow\/grant type.<\/p>\n<div id=\"attachment_21623\" style=\"width: 363px\" class=\"wp-caption aligncenter\"><img decoding=\"async\" aria-describedby=\"caption-attachment-21623\" class=\"wp-image-21623 size-full\" src=\"https:\/\/static.jamasoftware.com\/www\/imports\/2016\/05\/jama.png\" alt=\"Spring Security\" width=\"353\" height=\"114\" \/><p id=\"caption-attachment-21623\" class=\"wp-caption-text\">Jama OAuth service issues access tokens to clients of our system<\/p><\/div>\n<p>The access tokens are used to protect some REST resources. It was a <em>must have<\/em> requirement that the Jama OAuth service would support multi-tenancy. It was a natural choice to look at Spring Security, specifically <a class=\"jive-link-external-small\" href=\"http:\/\/projects.spring.io\/spring-security-oauth\/\" rel=\"nofollow\">Spring Security OAuth<\/a>. This library however, does not, out of the box, support multi-tenancy.<\/p>\n<p>When issuing access tokens, it is an interesting option to use JWT tokens. As <a class=\"jive-link-external-small\" href=\"http:\/\/jwt.io\/\" rel=\"nofollow\">this link<\/a> shows, JWT tokens are not just a unique identifier by which the authorization server can verify your claim, rather they do include the details of the claim. In our case we could include not only information about the <em>client<\/em>, but also about what tenant they belong to. Our tokens could look something like below, which is awesome, because it would mean that resources in our ecosystem can validate an access token (extract all the information that they need) without having to contact the Jama OAuth service, an enormous performance gain.<\/p>\n<pre class=\"lang:default decode:true \">{\n    \"exp\": 12345,\n    \"scope\": [\n        \"read\"\n    ],\n    \"tenant\": \"tenant1234\",\n    \"jti\": \"d08e06d9-7408-4a01-bcf0-409ad23391ce\",\n    \"client_id\": \"test1234\"\n}<\/pre>\n<p>This is almost exactly a JWT token that Spring Security OAuth spits out, using its <code>JwtAccessTokenConverter<\/code>, except for the custom property &#8220;<code>tenant<\/code>&#8220;. Unfortunately, there is no clear extension point to add custom properties. Conversely, when using Spring Security to validate an access token, what it gives your application code access to is an <code>OAuth2Request<\/code>, that does not include any custom properties. There is one more piece of tenant-awareness; in all we needed to address the following:<\/p>\n<ol>\n<li>Make sure that the application understands which is the right tenant when an access token is requested. This one is simple for us: we have standardized on including an HTTP request header that identifies the tenant. If you forget to include this header, you are awarded an error message. If you include this header, we can use it together with your provided user name and password, to authenticate your request. We would then proceed to return you an access token (JWT token), see the first list item here.<\/li>\n<li>Add custom property &#8220;<code>tenant<\/code>&#8221; to JWT tokens.<\/li>\n<li>Read custom property &#8220;<code>tenant<\/code>&#8221; from JWT tokens and make it available to our application code.<\/li>\n<\/ol>\n<h1>Add Custom Property<\/h1>\n<p>Creating tokens is a function of the authentication server (in our case the &#8220;Jama OAuth service&#8221;). JWT tokens are generated in Spring by the <code>JwtAccessTokenConverter<\/code>. So, of course we override that class to get our way. It is being configured in our Spring JavaConfig as follows:<\/p>\n<pre class=\"lang:default decode:true \">@Bean\npublic JwtAccessTokenConverter jwtAccessTokenConverter() throws Exception {\n    \/\/ specifically the following line:\n    JwtAccessTokenConverter converter = new TenantAwareJwtAccessTokenConverter();\n    converter.setKeyPair(keyPair);\n    return converter;\n}<\/pre>\n<p>Our custom implementation starts as follows:<\/p>\n<pre class=\"lang:default decode:true \">class TenantAwareJwtAccessTokenConverter extends JwtAccessTokenConverter { ...<\/pre>\n<p>Inside that class we retrieve the details of our client, which include the tenant, which we can then add to the access token:<\/p>\n<pre class=\"lang:default decode:true \">@Override\npublic OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {\n    ClientEntity clientEntity = getClientEntity(authentication);\n    Map&lt;String, Object&gt; info = new LinkedHashMap&lt;&gt;(accessToken.getAdditionalInformation());\n    info.putAll(clientEntity.getAdditionalInformationForToken()); \/\/ the additional information includes \"tenant\"=\"...\"\n    DefaultOAuth2AccessToken customAccessToken = new DefaultOAuth2AccessToken(accessToken);\n    customAccessToken.setAdditionalInformation(info);\n    return super.enhance(customAccessToken, authentication);\n}<\/pre>\n<p>When retrieving the details of our client we take the client ID given by Spring, and combine it with the tenant header from the request (that we require users to include when offering their client credentials).<\/p>\n<pre class=\"lang:default decode:true \">private ClientEntity getClientEntity(OAuth2Authentication authentication) {\n    String clientId = (String) authentication.getPrincipal();\n    String tenant = TenantHeaderHelper.getTenantFromRequest();\n    return getClientEntityFromDatabase(clientId, tenant); \/\/ this includes some assertions to make sure the requested client exists\n}<\/pre>\n<h1>Read Custom Property<\/h1>\n<p>This assumes that your resource server is also using Spring Security. It may or may not be the same component as your authentication server (in our case the &#8220;Jama OAuth service&#8221;). JWT tokens are processed in Spring by a small army of classes, but we chose to override <code>theDefaultAccessTokenConverter<\/code>. This needs to be injected into the <code>JwtAccessTokenConverter<\/code>, here of course our own <code>TenantAwareJwtAccessTokenConverter<\/code>. It is being configured in our Spring JavaConfig as follows:<\/p>\n<pre class=\"lang:default decode:true \">@Autowired\npublic void setJwtAccessTokenConverter(JwtAccessTokenConverter jwtAccessTokenConverter) {\n    jwtAccessTokenConverter.setAccessTokenConverter(defaultAccessTokenConverter());\n}\n\n@Bean\nDefaultAccessTokenConverter defaultAccessTokenConverter() {\n    return new TenantAwareAccessTokenConverter();\n}<\/pre>\n<p>Our custom implementation starts as follows:<\/p>\n<pre class=\"lang:default decode:true \">class TenantAwareAccessTokenConverter extends DefaultAccessTokenConverter { ...<\/pre>\n<p>Inside that class we can get access to a map that contains the raw data extracted from the JWT token, before Spring throws out our custom properties. Note that the <code>super<\/code> implementation already returns an <code>OAuth2Authentication<\/code> object. Inside that object, we substitute the <code>originalOAuth2Request<\/code> with our custom <code>TenantAwareOAuth2Request<\/code>.<\/p>\n<pre class=\"lang:default decode:true \">@Override\npublic OAuth2Authentication extractAuthentication(Map&lt;String, ?&gt; map) {\n    OAuth2Authentication authentication = super.extractAuthentication(map);\n    TenantAwareOAuth2Request tenantAwareOAuth2Request = new TenantAwareOAuth2Request(authentication.getOAuth2Request());\n    tenantAwareOAuth2Request.setTenant((String) map.get(\"tenant\"));\n    return new OAuth2Authentication(tenantAwareOAuth2Request, authentication.getUserAuthentication());\n}<\/pre>\n<p>Our custom <code>TenantAwareOAuth2Request<\/code> looks as follows. Thanks to a useful constructor in the base class (&#8220;copy constructor&#8221;) our custom class remains relatively simple.<\/p>\n<pre class=\"lang:default decode:true \">\/**\n * Add a tenant to the existing {@link OAuth2Request}.\n *\/\npublic class extends OAuth2Request {\n    public TenantAwareOAuth2Request(OAuth2Request other) {\n        super(other);\n    }\n\n    private String tenant;\n\n    public void setTenant(String tenant) {\n        this.tenant = tenant;\n    }\n\n    public String getTenant() {\n        return tenant;\n    }\n}<\/pre>\n<p>In your application code you can get access to this object in the usual ways, except casting to <code>TenantAwareOAuth2Request<\/code>, rather than <code>OAuth2Request<\/code>. Here is an application example:<\/p>\n<pre class=\"lang:default decode:true \">TenantAwareOAuth2Request request = getOAuth2RequestFromAuthentication();\nString clientId = request.getClientId();\nString tenant = request.getTenant();\n\/\/ do something with this information<\/pre>\n<div class=\"dp-highlighter\">\n<p>And:<\/p>\n<pre class=\"lang:default decode:true \">public static TenantAwareOAuth2Request getOAuth2RequestFromAuthentication() {\n    Authentication authentication = getAuthentication();\n    return getTenantAwareOAuth2Request(authentication);\n}\n\nprivate static TenantAwareOAuth2Request getTenantAwareOAuth2Request(Authentication authentication) {\n    if (!authentication.getClass().isAssignableFrom(OAuth2Authentication.class)) {\n        throw new RuntimeException(\"unexpected authentication object, expected OAuth2 authentication object\");\n    }\n    return (TenantAwareOAuth2Request) ((OAuth2Authentication) authentication).getOAuth2Request();\n}\n\nprivate static Authentication getAuthentication() {\n    SecurityContext securityContext = SecurityContextHolder.getContext();\n    return securityContext.getAuthentication();\n}<\/pre>\n<\/div>\n<p>If your resource server is not using Spring Security, there is other libraries to read JWT tokens, and to read the tenant off of these tokens. We have successfully used <a class=\"jive-link-external-small\" href=\"https:\/\/github.com\/jwtk\/jjwt\" rel=\"nofollow\">JJWT<\/a> for that.<\/p>\n<h1>Conclusion<\/h1>\n<p>While Spring Security does not make it very easy to add your own properties to JWT tokens, it can certainly be done in an acceptable manner. Having tenant information available in JWT tokens makes these tokens &#8220;fully qualified&#8221; in a multi-tenant environment, and thus usable without needing additional (tenant) information to be retrieved, when given an access token. This makes it also possible to do multi-tenant-enabled authentication, even on resource servers that aren&#8217;t the same component as your authentication server.<\/p>\n<p>You can see how this approach would work for additional properties, on top of just the &#8220;<code>tenant<\/code>&#8221; custom property. In fact, make sure that the JWT token contains just enough information so that resource servers can authorize the client without contacting the authorization server.<\/p>\n<input class=\"fooboxshare_post_id\" type=\"hidden\" value=\"20508\"\/>","protected":false},"excerpt":{"rendered":"<p>In being a SaaS company, we are gradually chipping away at our good old monolith, turning pieces into micro-services that can scale horizontally, and that scale efficiently by use of multi-tenancy. A single micro-service can have multiple instances, and each instance serves a multitude of customers. Multi-tenancy has implications on application state, and a common [&hellip;]<\/p>\n","protected":false},"author":4,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[4],"tags":[198,199,172,200,201,202],"industry":[],"class_list":["post-20508","post","type-post","status-publish","format-standard","hentry","category-company-news","tag-jwt-tokens","tag-multi-tenant","tag-rest-api","tag-saas","tag-spring-security","tag-spring-security-oauth"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v28.1 (Yoast SEO v28.1) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Extending Spring Security OAuth for Multi-Tenant - Jama Software<\/title>\n<meta name=\"description\" content=\"While Spring Security does not make it very easy to add your own properties to JWT tokens, it can certainly be done in an acceptable manner.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/08\/spring-security-oauth-multi-tenant\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Extending Spring Security OAuth for Multi-Tenant\" \/>\n<meta property=\"og:description\" content=\"While Spring Security does not make it very easy to add your own properties to JWT tokens, it can certainly be done in an acceptable manner.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/08\/spring-security-oauth-multi-tenant\/\" \/>\n<meta property=\"og:site_name\" content=\"Jama Software\" \/>\n<meta property=\"article:published_time\" content=\"2016-06-08T17:00:36+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-01-13T00:55:34+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/static.jamasoftware.com\/www\/imports\/2016\/05\/jama.png\" \/>\n<meta name=\"author\" content=\"Jama Software\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Jama Software\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/blog\\\/2016\\\/06\\\/08\\\/spring-security-oauth-multi-tenant\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/blog\\\/2016\\\/06\\\/08\\\/spring-security-oauth-multi-tenant\\\/\"},\"author\":{\"name\":\"Jama Software\",\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/#\\\/schema\\\/person\\\/59a942565a528aa5f56b240c9342fc7f\"},\"headline\":\"Extending Spring Security OAuth for Multi-Tenant\",\"datePublished\":\"2016-06-08T17:00:36+00:00\",\"dateModified\":\"2023-01-13T00:55:34+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/blog\\\/2016\\\/06\\\/08\\\/spring-security-oauth-multi-tenant\\\/\"},\"wordCount\":945,\"image\":{\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/blog\\\/2016\\\/06\\\/08\\\/spring-security-oauth-multi-tenant\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/static.jamasoftware.com\\\/www\\\/imports\\\/2016\\\/05\\\/jama.png\",\"keywords\":[\"JWT tokens\",\"Multi-Tenant\",\"REST API\",\"SaaS\",\"Spring Security\",\"Spring Security OAuth\"],\"articleSection\":[\"Jama Software Company and Community News\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/blog\\\/2016\\\/06\\\/08\\\/spring-security-oauth-multi-tenant\\\/\",\"url\":\"https:\\\/\\\/www.jamasoftware.com\\\/blog\\\/2016\\\/06\\\/08\\\/spring-security-oauth-multi-tenant\\\/\",\"name\":\"Extending Spring Security OAuth for Multi-Tenant - Jama Software\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/blog\\\/2016\\\/06\\\/08\\\/spring-security-oauth-multi-tenant\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/blog\\\/2016\\\/06\\\/08\\\/spring-security-oauth-multi-tenant\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/static.jamasoftware.com\\\/www\\\/imports\\\/2016\\\/05\\\/jama.png\",\"datePublished\":\"2016-06-08T17:00:36+00:00\",\"dateModified\":\"2023-01-13T00:55:34+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/#\\\/schema\\\/person\\\/59a942565a528aa5f56b240c9342fc7f\"},\"description\":\"While Spring Security does not make it very easy to add your own properties to JWT tokens, it can certainly be done in an acceptable manner.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/blog\\\/2016\\\/06\\\/08\\\/spring-security-oauth-multi-tenant\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.jamasoftware.com\\\/blog\\\/2016\\\/06\\\/08\\\/spring-security-oauth-multi-tenant\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/blog\\\/2016\\\/06\\\/08\\\/spring-security-oauth-multi-tenant\\\/#primaryimage\",\"url\":\"https:\\\/\\\/static.jamasoftware.com\\\/www\\\/imports\\\/2016\\\/05\\\/jama.png\",\"contentUrl\":\"https:\\\/\\\/static.jamasoftware.com\\\/www\\\/imports\\\/2016\\\/05\\\/jama.png\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/blog\\\/2016\\\/06\\\/08\\\/spring-security-oauth-multi-tenant\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.jamasoftware.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Extending Spring Security OAuth for Multi-Tenant\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/#website\",\"url\":\"https:\\\/\\\/www.jamasoftware.com\\\/\",\"name\":\"Jama Software\",\"description\":\"Jama Connect\u00ae #1 in Requirements Management\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.jamasoftware.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/#\\\/schema\\\/person\\\/59a942565a528aa5f56b240c9342fc7f\",\"name\":\"Jama Software\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/6e1172c5d380b2a20a9e5b5a4c0fb4e38bc497dc27ce100567da29abe37001af?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/6e1172c5d380b2a20a9e5b5a4c0fb4e38bc497dc27ce100567da29abe37001af?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/6e1172c5d380b2a20a9e5b5a4c0fb4e38bc497dc27ce100567da29abe37001af?s=96&d=mm&r=g\",\"caption\":\"Jama Software\"},\"description\":\"Subject matter experts from Jama Software provide guidance and best practices on requirements management, test management, compliance and regulation, risk management, and complex product and software development.\",\"url\":\"https:\\\/\\\/www.jamasoftware.com\\\/blog\\\/author\\\/jama-software\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Extending Spring Security OAuth for Multi-Tenant - Jama Software","description":"While Spring Security does not make it very easy to add your own properties to JWT tokens, it can certainly be done in an acceptable manner.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/08\/spring-security-oauth-multi-tenant\/","og_locale":"en_US","og_type":"article","og_title":"Extending Spring Security OAuth for Multi-Tenant","og_description":"While Spring Security does not make it very easy to add your own properties to JWT tokens, it can certainly be done in an acceptable manner.","og_url":"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/08\/spring-security-oauth-multi-tenant\/","og_site_name":"Jama Software","article_published_time":"2016-06-08T17:00:36+00:00","article_modified_time":"2023-01-13T00:55:34+00:00","og_image":[{"url":"https:\/\/static.jamasoftware.com\/www\/imports\/2016\/05\/jama.png","type":"","width":"","height":""}],"author":"Jama Software","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Jama Software","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/08\/spring-security-oauth-multi-tenant\/#article","isPartOf":{"@id":"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/08\/spring-security-oauth-multi-tenant\/"},"author":{"name":"Jama Software","@id":"https:\/\/www.jamasoftware.com\/#\/schema\/person\/59a942565a528aa5f56b240c9342fc7f"},"headline":"Extending Spring Security OAuth for Multi-Tenant","datePublished":"2016-06-08T17:00:36+00:00","dateModified":"2023-01-13T00:55:34+00:00","mainEntityOfPage":{"@id":"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/08\/spring-security-oauth-multi-tenant\/"},"wordCount":945,"image":{"@id":"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/08\/spring-security-oauth-multi-tenant\/#primaryimage"},"thumbnailUrl":"https:\/\/static.jamasoftware.com\/www\/imports\/2016\/05\/jama.png","keywords":["JWT tokens","Multi-Tenant","REST API","SaaS","Spring Security","Spring Security OAuth"],"articleSection":["Jama Software Company and Community News"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/08\/spring-security-oauth-multi-tenant\/","url":"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/08\/spring-security-oauth-multi-tenant\/","name":"Extending Spring Security OAuth for Multi-Tenant - Jama Software","isPartOf":{"@id":"https:\/\/www.jamasoftware.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/08\/spring-security-oauth-multi-tenant\/#primaryimage"},"image":{"@id":"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/08\/spring-security-oauth-multi-tenant\/#primaryimage"},"thumbnailUrl":"https:\/\/static.jamasoftware.com\/www\/imports\/2016\/05\/jama.png","datePublished":"2016-06-08T17:00:36+00:00","dateModified":"2023-01-13T00:55:34+00:00","author":{"@id":"https:\/\/www.jamasoftware.com\/#\/schema\/person\/59a942565a528aa5f56b240c9342fc7f"},"description":"While Spring Security does not make it very easy to add your own properties to JWT tokens, it can certainly be done in an acceptable manner.","breadcrumb":{"@id":"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/08\/spring-security-oauth-multi-tenant\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.jamasoftware.com\/blog\/2016\/06\/08\/spring-security-oauth-multi-tenant\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/08\/spring-security-oauth-multi-tenant\/#primaryimage","url":"https:\/\/static.jamasoftware.com\/www\/imports\/2016\/05\/jama.png","contentUrl":"https:\/\/static.jamasoftware.com\/www\/imports\/2016\/05\/jama.png"},{"@type":"BreadcrumbList","@id":"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/08\/spring-security-oauth-multi-tenant\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.jamasoftware.com\/"},{"@type":"ListItem","position":2,"name":"Extending Spring Security OAuth for Multi-Tenant"}]},{"@type":"WebSite","@id":"https:\/\/www.jamasoftware.com\/#website","url":"https:\/\/www.jamasoftware.com\/","name":"Jama Software","description":"Jama Connect\u00ae #1 in Requirements Management","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.jamasoftware.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.jamasoftware.com\/#\/schema\/person\/59a942565a528aa5f56b240c9342fc7f","name":"Jama Software","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/6e1172c5d380b2a20a9e5b5a4c0fb4e38bc497dc27ce100567da29abe37001af?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/6e1172c5d380b2a20a9e5b5a4c0fb4e38bc497dc27ce100567da29abe37001af?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/6e1172c5d380b2a20a9e5b5a4c0fb4e38bc497dc27ce100567da29abe37001af?s=96&d=mm&r=g","caption":"Jama Software"},"description":"Subject matter experts from Jama Software provide guidance and best practices on requirements management, test management, compliance and regulation, risk management, and complex product and software development.","url":"https:\/\/www.jamasoftware.com\/blog\/author\/jama-software\/"}]}},"_links":{"self":[{"href":"https:\/\/www.jamasoftware.com\/legacy\/wp-json\/wp\/v2\/posts\/20508","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.jamasoftware.com\/legacy\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.jamasoftware.com\/legacy\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.jamasoftware.com\/legacy\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/www.jamasoftware.com\/legacy\/wp-json\/wp\/v2\/comments?post=20508"}],"version-history":[{"count":0,"href":"https:\/\/www.jamasoftware.com\/legacy\/wp-json\/wp\/v2\/posts\/20508\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.jamasoftware.com\/legacy\/wp-json\/wp\/v2\/media?parent=20508"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.jamasoftware.com\/legacy\/wp-json\/wp\/v2\/categories?post=20508"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.jamasoftware.com\/legacy\/wp-json\/wp\/v2\/tags?post=20508"},{"taxonomy":"industry","embeddable":true,"href":"https:\/\/www.jamasoftware.com\/legacy\/wp-json\/wp\/v2\/industry?post=20508"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}