{"id":61622,"date":"2016-11-14T10:02:10","date_gmt":"2016-11-14T08:02:10","guid":{"rendered":"http:\/\/www.javacodegeeks.com\/?p=61622"},"modified":"2016-11-22T08:30:38","modified_gmt":"2016-11-22T06:30:38","slug":"oauth-2-0-token-management-stormpath-spring-boot","status":"publish","type":"post","link":"https:\/\/www.javacodegeeks.com\/2016\/11\/oauth-2-0-token-management-stormpath-spring-boot.html","title":{"rendered":"OAuth 2.0 Token Management with Stormpath and Spring Boot"},"content":{"rendered":"<p><span style=\"font-size: 20px;\">Building Identity Management, including authentication and authorization? Try Stormpath! Our REST API and <a href=\"https:\/\/docs.stormpath.com\/java\/?utm_source=java-code-geeks&#038;utm_medium=post&#038;utm_content=spring-boot-token-management&#038;utm_campaign=spring-java-2016\">robust Java SDK support<\/a> can eliminate your security risk and can be implemented in minutes. <a href=\"https:\/\/api.stormpath.com\/register?utm_source=java-code-geeks&#038;utm_medium=post&#038;utm_content=spring-boot-token-management&#038;utm_campaign=spring-java-2016\">Sign up<\/a>, and never build auth again!<\/span><\/p>\n<p>OAuth 2.0 token management is often misunderstood and difficult to implement correctly. Fortunately, with Stormpath\u2019s SDKs and integrations, we make Token Management easy \u2013 fun, even. This 20-minute tutorial will show you how to implement Token Management with Stormpath\u2019s Spring Boot and Spring Security integrations.<\/p>\n<p>While Spring Security <em>does<\/em> have built in OAuth 2.0 support, there is no native token management support in Spring Boot, and working with the OAuth protocol has been known to cause spontaneous outbreaks of hives, cold sweats, and prolonged \u201cface desking.\u201d<\/p>\n<p><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/face_desk.gif\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-61623\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/face_desk.gif\" alt=\"face_desk\" width=\"500\" height=\"388\" \/><\/a><\/p>\n<p>Stormpath\u2019s Spring Boot integration supports two OAuth flows: <code>grant_type=password<\/code> and <code>grant_type=refresh_token<\/code>. The Password Grant Type allows you to pass in a username and password and get back an Access Token and a Refresh Token. The Refresh Token Grant Type allows you to pass in a Refresh Token and get back a new Access Token.<\/p>\n<p>They are both accessed through a single endpoint, <code>\/oauth\/token<\/code>, which is available out of the box with the Stormpath integration. So, fear not! Stormpath\u2019s Token Management does all the heavy lifting. You just have to create the HTTP request using some basic rules discussed below.<\/p>\n<h2>Resources for This Tutorial<\/h2>\n<p>By then end of this post, you\u2019ll have everything you need to swap a username and password for a set of tokens that allows a user to access restricted resources in an application. You\u2019ll also be able to refresh and revoke tokens to provide a fine degree of control over how users access your application and how long they stay logged in.<\/p>\n<p>The code that backs this post is <a href=\"https:\/\/github.com\/stormpath\/stormpath-default-spring-boot-token-management-example\">here<\/a>.<\/p>\n<p>You can see the example in action at: <a href=\"https:\/\/jquery-spa.herokuapp.com\/\">https:\/\/jquery-spa.herokuapp.com<\/a> (due to the Heroku <a href=\"https:\/\/devcenter.heroku.com\/articles\/dyno-sleeping\">sleep<\/a>policy, you may have to wait a few seconds for the app to respond initially) and you can deploy it to your Heroku account <em>right now<\/em> using the button below.<\/p>\n<p><a href=\"https:\/\/signup.heroku.com\/deploy?redirect-url=https%3A%2F%2Fdashboard.heroku.com%2Fnew%3Fbutton-url%3Dhttps%253A%252F%252Fstormpath.com%252Fblog%252Ffun-with-java-spring-boot-token-management%26template%3Dhttps%253A%252F%252Fgithub.com%252Fstormpath%252Fstormpath-default-spring-boot-token-management-example\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-61624\" style=\"border:none\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/button.png\" alt=\"button\" width=\"147\" height=\"32\" \/><\/a><\/p>\n<p>While Token Management is typically a behind-the-scenes affair, this example uses a SPA or Single Page Application. To keep the example simple (and Javascript framework-agnostic), all calls are made using <a href=\"http:\/\/api.jquery.com\/jquery.ajax\/\">jQuery\u2019s ajax<\/a> functionality.<\/p>\n<h2>Modern Token Management \u2013 Access and Refresh Tokens<\/h2>\n<p>In a modern application that supports OAuth 2.0 Token Management, a user\u2019s session typically has one Access Token with a short expiration and one Refresh Token with a longer expiration. When the Access Token expires, the application will use the Refresh Token to obtain a new Access Token. This process is repeated until the Refresh Token expires. At this point, the user would need to log into the application again.<\/p>\n<p>For a deep dive into OAuth tokens and how they work, check out my colleague Randall\u2019s <a href=\"http:\/\/stormpath.com\/blog\/what-the-heck-is-oauth\/?utm_source=java-code-geeks&amp;utm_medium=post&amp;utm_content=spring-boot-token-management&amp;utm_campaign=spring-java-2016\">post that explores OAuth in detail<\/a>.<\/p>\n<h2>JSON Web Token (JWT) Security PSA<\/h2>\n<p>The OAuth 2.0 specification does not specify a particular token format, so Stormpath uses JWTs to represent Access Tokens and Refresh Tokens. JWTs have additional information encoded into them, and more importantly, they are cryptographically signed to provide conclusive evidence that the token has not been tampered with.<\/p>\n<p>Stormpath Access Tokens also provide an important layer of additional security \u2013 they always contain a reference to the associated Refresh Token. This reference is a claim identified by the code <code>rti<\/code>. It\u2019s one of the ways Stormpath ensures it is an Access Token being used to access a protected resource and not a Refresh Token. Other implementations of OAuth 2.0 have (inadvertently) allowed a refresh token to act as an access token, giving users longer access then they should have. We guard against that.<\/p>\n<p>If you want to learn more about JWTs and how to use them securely, check out our posts on how to <a href=\"http:\/\/stormpath.com\/blog\/jwt-the-right-way\/?utm_source=java-code-geeks&amp;utm_medium=post&amp;utm_content=spring-boot-token-management&amp;utm_campaign=spring-java-2016\">Use JWTs the Right Way<\/a>, <a href=\"http:\/\/stormpath.com\/blog\/build-secure-user-interfaces-using-jwts\/?utm_source=java-code-geeks&amp;utm_medium=post&amp;utm_content=spring-boot-token-management&amp;utm_campaign=spring-java-2016\">Build Secure User Interfaces with JWTs<\/a>, and <a href=\"http:\/\/stormpath.com\/blog\/where-to-store-your-jwts-cookies-vs-html5-web-storage\/?utm_source=java-code-geeks&amp;utm_medium=post&amp;utm_content=spring-boot-token-management&amp;utm_campaign=spring-java-2016\">Where to Store Your JWTs<\/a>.<\/p>\n<p>OK, with all that out of the way, let\u2019s get started!<\/p>\n<h2>Spring Security Configuration<\/h2>\n<p>In the sections that follow, we\u2019re going to explore the example application through the lens of the jQuery calls that are made to the backend <code>\/oauth\/token<\/code> endpoint in the Spring Boot application.<div style=\"display:inline-block; margin: 15px 0;\"> <div id=\"adngin-JavaCodeGeeks_incontent_video-0\" style=\"display:inline-block;\"><\/div> <\/div><\/p>\n<p>Before we get to that, let\u2019s look at the Spring Security configuration for this example application:<\/p>\n<pre class=\"brush:java\">@Configuration\r\npublic class SpringSecurityWebAppConfig extends WebSecurityConfigurerAdapter {\r\n \r\n    @Override\r\n    protected void configure(HttpSecurity http) throws Exception {\r\n        http.apply(stormpath()).and()\r\n            .authorizeRequests()\r\n            .antMatchers(\"\/\").permitAll()\r\n            .antMatchers(\"\/decode\").permitAll()\r\n            .antMatchers(\"\/static\/**\").permitAll();\r\n    }\r\n}<\/pre>\n<p>Stormpath\u2019s Spring Security integration follows the default access configuration for Spring Security, which is that all paths are locked down.<\/p>\n<p>In the above configuration, we are allowing unauthenticated access to <code>\/<\/code> and <code>\/decode<\/code> as well as any path within <code>\/static<\/code>. We\u2019ll see this in action as we work through the example below.<\/p>\n<h2>Let\u2019s Get Some Tokens<\/h2>\n<p>There are two primary static files in our SPA example: <code>home.html<\/code> and <code>static\/js\/token-management-guided-tour.js<\/code>.<\/p>\n<p><code>home.html<\/code> is a <a href=\"http:\/\/www.thymeleaf.org\/\">Thymeleaf<\/a> template in which the <code>static\/js\/token-management-guided-tour.js<\/code>Javascript file is loaded.<\/p>\n<p>Here\u2019s a view of the different sections of <code>home.html<\/code>:<\/p>\n<p><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/home1.png\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-61625\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/home1.png\" alt=\"home1\" width=\"687\" height=\"682\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/home1.png 687w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/home1-150x150.png 150w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/home1-300x298.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/home1-70x70.png 70w\" sizes=\"(max-width: 687px) 100vw, 687px\" \/><\/a><\/p>\n<p>It\u2019s broken down into 7 steps and the application walks you through the example, \u201cguided tour\u201d style.<\/p>\n<p>The first step is to pass in an email and password and get back Access and Refresh Tokens. Let\u2019s look at that in action.<\/p>\n<h3>Login with Email and Password<\/h3>\n<p>Here\u2019s the jQuery code that processes the initial request to the <code>\/oauth\/token<\/code> endpoint (<code>error<\/code> and <code>complete<\/code> functions omitted for brevity):<\/p>\n<pre class=\"brush:java\">$('#login-form').submit(function (e) {\r\n \r\n    var theForm = $('#login-form');\r\n \r\n    $.ajax({\r\n        type: 'post',\r\n        url: '\/oauth\/token',\r\n        data: theForm.serialize(),\r\n        success: function (data) {\r\n            accessToken = data.access_token;\r\n            refreshToken = data.refresh_token;\r\n            var accessTokenParts = accessToken.split('.');\r\n            $.each(['header', 'payload', 'signature'], function (index, value) {\r\n                $('#access-token-' + value).html(accessTokenParts[index]);\r\n            });\r\n            $('#login-error').hide();\r\n            showOnlyDiv('access-token-div');\r\n        }\r\n    });\r\n \r\n    e.preventDefault();\r\n});<\/pre>\n<p>Line 3 gives us a handle to the form.<\/p>\n<p>Per the <a href=\"https:\/\/tools.ietf.org\/html\/rfc6749#section-4.3\">OAuth<\/a> spec, the method will be <code>POST<\/code> and the <code>Content-Type<\/code> is <code>application\/x-www-form-urlencoded<\/code> (this is the default for jQuery\u2019s <code>$.ajax<\/code> call). The data passed to <code>\/oauth\/token<\/code> will look like this:<\/p>\n<pre class=\"brush:bash\">grant_type=password&amp;username=&lt;username&gt;&amp;password=&lt;password&gt;<\/pre>\n<p>This is the result of the call to <code>theForm.serialize()<\/code> on line 8.<\/p>\n<p>The success handler which begins on line 9 stores the <code>access_token<\/code> and the <code>refresh_token<\/code> in local variables. It also displays the parts of the <code>access_token<\/code> (header, payload, and signature) in your browser as a visual representation of the JWT:<\/p>\n<p><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/access_token.png\"><img decoding=\"async\" class=\"aligncenter wp-image-61626\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/access_token.png\" alt=\"access_token\" width=\"860\" height=\"393\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/access_token.png 888w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/access_token-300x137.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/access_token-768x351.png 768w\" sizes=\"(max-width: 860px) 100vw, 860px\" \/><\/a><\/p>\n<p>Note: As the screenshot shows, the example app is for demonstration purposes only. In \u201creal life\u201d you would not want to show an Access Token in the browser and you would want to use best practices for storing tokens in your client app. We have a great post on those best practices <a href=\"http:\/\/stormpath.com\/blog\/where-to-store-your-jwts-cookies-vs-html5-web-storage\/?utm_source=java-code-geeks&amp;utm_medium=post&amp;utm_content=spring-boot-token-management&amp;utm_campaign=spring-java-2016\">here<\/a>.<\/p>\n<h3>Anatomy of a Stormpath Access Token<\/h3>\n<p>In the example app, if you click on the <code>Decode<\/code> button, you will see something like the following:<\/p>\n<p><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/decoded.png\"><img decoding=\"async\" class=\"aligncenter wp-image-61627\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/decoded.png\" alt=\"decoded\" width=\"860\" height=\"303\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/decoded.png 876w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/decoded-300x106.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/decoded-768x271.png 768w\" sizes=\"(max-width: 860px) 100vw, 860px\" \/><\/a><\/p>\n<p>This shows you the header and the payload sections of the JWT that are the Access Token. To understand how we decoded our Access Token, we need to take a look at the <code>decode<\/code> method in the <code>APIController<\/code> in the example app:<\/p>\n<pre class=\"brush:java\">@RequestMapping(\"\/decode\")\r\npublic Jws&lt;Claims&gt; decode(@RequestParam String token) throws UnsupportedEncodingException {\r\n \r\n    Jws&lt;Claims&gt; claims = Jwts.parser()\r\n        .setSigningKey(client.getApiKey().getSecret().getBytes(\"UTF-8\"))\r\n        .parseClaimsJws(token);\r\n \r\n    return claims;\r\n}<\/pre>\n<p>The method takes a JWT (which in this case is our Access Token) as a parameter and uses the <a href=\"https:\/\/java.jsonwebtoken.io\/\">JJWT<\/a>library to parse out the claims. It also verifies that the JWT signature is valid as part of the parsing process. To do this, it uses the secret from the Stormpath Client which was used to create the JWT in the first place.<\/p>\n<p>Finally, the method returns the <code>Jws&lt;Claims&gt;<\/code> object. This is where Spring Boot\u2019s automatic Jackson JSON mapper kicks in and converts that object to JSON. Here\u2019s what the raw response looks like:<\/p>\n<pre class=\"brush:bash\">{\r\n    \"header\": {\r\n        \"kid\": \"R92SBHJC1U4DAIMGQ3MHOGVMX\",\r\n        \"alg\": \"HS256\"\r\n    },\r\n    \"body\": {\r\n        \"jti\": \"6UBPQ975cDDiz8ckHqWIZF\",\r\n        \"iat\": 1456242057,\r\n        \"iss\": \"https:\/\/api.stormpath.com\/v1\/applications\/2nBCvauLgETX8wO0VvS9mQ\",\r\n        \"sub\": \"https:\/\/api.stormpath.com\/v1\/accounts\/49CK1VvY2jQwUBH7UnP5zC\",\r\n        \"exp\": 1456245657,\r\n        \"rti\": \"6UBPQ5n0hcukMJWt5af1xB\"\r\n    },\r\n    \"signature\": \"Pm30FjdXOmx_fMGhfku85Z9xc6qE-EZgKHI4mV46KO8\"\r\n}<\/pre>\n<p>Notice that the <code>body<\/code> (payload) of the decoded JWT includes a reference to the Stormpath Account in the <code>sub<\/code> (subject) claim. It is this Account that is used when accessing restricted resources as we will see next.<\/p>\n<h2>Using an Access Token<\/h2>\n<p>After decoding the Access Token, the next step in our example app\u2019s guided tour is to hit a restricted resource using that Access Token. Here\u2019s the jQuery code that accomplishes that:<\/p>\n<pre class=\"brush:java\">$('#restricted').click(function () {\r\n \r\n    $('#account-info-table tbody').empty();\r\n    $.ajax({\r\n        type: 'get',\r\n        url: '\/restricted',\r\n        success: function (data) {\r\n            var newRowContent = '&lt;tr&gt;&lt;td&gt;' + data.fullName + '&lt;\/td&gt;&lt;td&gt;' + data.email + '&lt;\/td&gt;&lt;\/tr&gt;';\r\n            $('#account-info-table tbody').append(newRowContent);\r\n            showOnlyDiv('account-info-div');\r\n        }\r\n    })\r\n});<\/pre>\n<p>You may be wondering where the authentication is in the above code. Cookies were set in the browser in the steps above when you logged in. If you look at the inspector in your browser, you will see that the <code>access_token<\/code> is passed up to the request to the <code>\/restricted<\/code> endpoint. In a separate browser session, you can try hitting: <code>http:\/\/localhost:8080\/restricted<\/code>. You will be redirected to <code>\/login<\/code>. This is a function of our Spring Security configuration. The <code>\/restricted<\/code> path was <em>not<\/em> one of the paths that we explicitly allowed in the Spring Security configuration and as such, the request must be authenticated. To understand the response from <code>\/restricted<\/code>, let\u2019s look at the <code>restricted<\/code> method in the <code>APIController<\/code>:<\/p>\n<pre class=\"brush:java\">@RequestMapping(\"\/restricted\")\r\npublic AccountInfo restricted(HttpServletRequest req) {\r\n    Account account = AccountResolver.INSTANCE.getAccount(req);\r\n    return new AccountInfo(account.getFullName(), account.getEmail());\r\n}<\/pre>\n<p>This is simply returning an <code>AccountInfo<\/code> model object that has the full name and email address of the authenticated user. The <code>AccountInfo<\/code> object defined in the example app is easily converted to JSON by the same automatic Spring Boot mapper process that we saw above.<\/p>\n<p>The jQuery <code>success<\/code> function above displays the Account information returned from the request to <code>\/restricted<\/code>.<\/p>\n<h2>Token Management: It\u2019s Refreshing!<\/h2>\n<p>The next step in our journey is to use the Refresh Token to obtain a new Access Token. In a typical mobile application, the following would happen behind the scenes without the user ever knowing:<\/p>\n<ol>\n<li>The current Access Token expires<\/li>\n<li>The user tries to access a restricted part of the application using the (expired) Access Token<\/li>\n<li>The application receives a <a href=\"https:\/\/tools.ietf.org\/html\/rfc7235#section-3.1\"><code>401<\/code><\/a> (unauthorized) HTTP response code<\/li>\n<li>The application uses the Refresh Token to obtain a new Access Token<\/li>\n<li>The application tries to access the restricted part of the application using the new Access Token<\/li>\n<li>The user sees the result of that request without having to log in again<\/li>\n<\/ol>\n<p>Note: If the Refresh Token has expired, then the user of the application would need to log in again at Step 4<\/p>\n<p>Stormpath provides an OAuth Policy in the admin console to set expirations for Access Tokens and Refresh Tokens.<\/p>\n<h3>A Look at the OAuth Policy<\/h3>\n<p>Here\u2019s what the OAuth Policy looks like in the Stormpath Admin Console:<\/p>\n<p><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/oauth_policy.png\"><img decoding=\"async\" class=\"aligncenter wp-image-61628\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/oauth_policy.png\" alt=\"oauth_policy\" width=\"860\" height=\"576\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/oauth_policy.png 1039w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/oauth_policy-300x201.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/oauth_policy-768x514.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/oauth_policy-1024x686.png 1024w\" sizes=\"(max-width: 860px) 100vw, 860px\" \/><\/a><\/p>\n<p>The default time-to-live for Access Tokens is 1 hour and the default TTL for Refresh Tokens is 60 days.<\/p>\n<h3>Refreshing the Access Token<\/h3>\n<p>When you click the <code>Refresh the Access Token<\/code> button in the example app, you get a response that looks like this:<\/p>\n<p><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/refresh.png\"><img decoding=\"async\" class=\"aligncenter wp-image-61629\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/refresh.png\" alt=\"refresh\" width=\"860\" height=\"575\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/refresh.png 880w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/refresh-300x200.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/refresh-768x513.png 768w\" sizes=\"(max-width: 860px) 100vw, 860px\" \/><\/a><\/p>\n<p>This displays the new Access Token retrieved in the refresh process. To understand what\u2019s going on there, we turn back to our jQuery code (success handler omitted for brevity):<\/p>\n<pre class=\"brush:java\">$('#refresh').click(function () {\r\n \r\n    $.ajax({\r\n        type: 'post',\r\n        url: '\/oauth\/token',\r\n        data: 'grant_type=refresh_token&amp;refresh_token=' + refreshToken,\r\n        success: function (data) {\r\n        }\r\n    })\r\n});<\/pre>\n<p>Once again, we are making an HTTP <code>POST<\/code> to the <code>\/oauth\/token<\/code> endpoint. Unlike the <code>grant_type=password<\/code> flow, in this instance we are using <code>grant_type=refresh_token<\/code> and we are passing in the Refresh Token we saved from earlier.<\/p>\n<p>The response from this ajax call is a new Access Token which is then displayed in the browser underneath the old Access Token.<\/p>\n<h2>Kick that Token to the Curb<\/h2>\n<p>The last part of our Token Management joyride is revoking the Access and Refresh Tokens. This is accomplished by hitting the (built-in) <code>\/logout<\/code> endpoint providing the Access Token as a Bearer token, as we did when hitting a restricted resource earlier. Let\u2019s look at the jQuery code that accomplishes this:<\/p>\n<pre class=\"brush:java\">$('#revoke').click(function () {\r\n \r\n    $.ajax({\r\n        type: 'post',\r\n        url: '\/logout',\r\n        success: function () {\r\n            showOnlyDiv('revoke-div');\r\n        }\r\n    })\r\n});<\/pre>\n<p>We\u2019re sending an HTTP <code>POST<\/code> request to <code>\/logout<\/code>. The cookies containing the <code>access_token<\/code> and <code>refresh_token<\/code> are removed at this point and the tokens are revoked on the Stormpath backend. This is handled automatically behind the scenes.<\/p>\n<p>The example app tries to hit the <code>\/restricted<\/code> path again. The result looks like this:<\/p>\n<p><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/fail.png\"><img decoding=\"async\" class=\"aligncenter wp-image-61632\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/fail.png\" alt=\"fail\" width=\"860\" height=\"320\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/fail.png 877w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/fail-300x112.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/fail-768x285.png 768w\" sizes=\"(max-width: 860px) 100vw, 860px\" \/><\/a><\/p>\n<p>The result shows that trying to use a deleted Access Token will not work.<\/p>\n<h2>In Summary<\/h2>\n<p>The <code>\/oauth\/token<\/code> endpoint provided out-of-the-box in Stormpath\u2019s Spring Boot integration enables all the functionality of a modern Token Management system.<\/p>\n<p>In this post, we\u2019ve covered what Access and Refresh tokens are, as well as how they are obtained, used, refreshed, and revoked.<\/p>\n<p>You can see the example application used throughout this post at: <a href=\"https:\/\/jquery-spa.herokuapp.com\/\">https:\/\/jquery-spa.herokuapp.com<\/a> or, you can use the button below to deploy the app to your own Heroku account.<\/p>\n<p><a href=\"https:\/\/signup.heroku.com\/deploy?redirect-url=https%3A%2F%2Fdashboard.heroku.com%2Fnew%3Fbutton-url%3Dhttps%253A%252F%252Fstormpath.com%252Fblog%252Ffun-with-java-spring-boot-token-management%26template%3Dhttps%253A%252F%252Fgithub.com%252Fstormpath%252Fstormpath-default-spring-boot-token-management-example\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-61633\" style=\"border:none\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/11\/button-1.png\" alt=\"button\" width=\"147\" height=\"32\" \/><\/a><\/p>\n<p><span style=\"font-size: 20px;\">Building Identity Management, including authentication and authorization? Try Stormpath! Our REST API and <a href=\"https:\/\/docs.stormpath.com\/java\/?utm_source=java-code-geeks&#038;utm_medium=post&#038;utm_content=spring-boot-token-management&#038;utm_campaign=spring-java-2016\">robust Java SDK support<\/a> can eliminate your security risk and can be implemented in minutes. <a href=\"https:\/\/api.stormpath.com\/register?utm_source=java-code-geeks&#038;utm_medium=post&#038;utm_content=spring-boot-token-management&#038;utm_campaign=spring-java-2016\">Sign up<\/a>, and never build auth again!<\/span><\/p>\n<p><a href=\"https:\/\/api.stormpath.com\/register?utm_source=java-code-geeks&#038;utm_medium=post&#038;utm_content=spring-boot-token-management&#038;utm_campaign=spring-java-2016\"><img decoding=\"async\" style=\"border:none\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2016\/09\/button-sign-up-now.png\" alt=\"button-sign-up-now\" width=\"180\" height=\"51\" class=\"aligncenter size-full wp-image-60632\" \/><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Building Identity Management, including authentication and authorization? Try Stormpath! Our REST API and robust Java SDK support can eliminate your security risk and can be implemented in minutes. Sign up, and never build auth again! OAuth 2.0 token management is often misunderstood and difficult to implement correctly. Fortunately, with Stormpath\u2019s SDKs and integrations, we make &hellip;<\/p>\n","protected":false},"author":1062,"featured_media":240,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[30,854],"class_list":["post-61622","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-enterprise-java","tag-spring","tag-spring-boot"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>OAuth 2.0 Token Management with Stormpath and Spring Boot - Java Code Geeks<\/title>\n<meta name=\"description\" content=\"Building Identity Management, including authentication and authorization? Try Stormpath! Our REST API and robust Java SDK support can eliminate your\" \/>\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.javacodegeeks.com\/2016\/11\/oauth-2-0-token-management-stormpath-spring-boot.html\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"OAuth 2.0 Token Management with Stormpath and Spring Boot - Java Code Geeks\" \/>\n<meta property=\"og:description\" content=\"Building Identity Management, including authentication and authorization? Try Stormpath! Our REST API and robust Java SDK support can eliminate your\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.javacodegeeks.com\/2016\/11\/oauth-2-0-token-management-stormpath-spring-boot.html\" \/>\n<meta property=\"og:site_name\" content=\"Java Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/javacodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2016-11-14T08:02:10+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2016-11-22T06:30:38+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Micah Silverman\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:site\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Micah Silverman\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2016\\\/11\\\/oauth-2-0-token-management-stormpath-spring-boot.html#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2016\\\/11\\\/oauth-2-0-token-management-stormpath-spring-boot.html\"},\"author\":{\"name\":\"Micah Silverman\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/fd211fe0d3a9791d30dd0ca5276d9660\"},\"headline\":\"OAuth 2.0 Token Management with Stormpath and Spring Boot\",\"datePublished\":\"2016-11-14T08:02:10+00:00\",\"dateModified\":\"2016-11-22T06:30:38+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2016\\\/11\\\/oauth-2-0-token-management-stormpath-spring-boot.html\"},\"wordCount\":1919,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2016\\\/11\\\/oauth-2-0-token-management-stormpath-spring-boot.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/spring-logo.jpg\",\"keywords\":[\"Spring\",\"Spring Boot\"],\"articleSection\":[\"Enterprise Java\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2016\\\/11\\\/oauth-2-0-token-management-stormpath-spring-boot.html#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2016\\\/11\\\/oauth-2-0-token-management-stormpath-spring-boot.html\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2016\\\/11\\\/oauth-2-0-token-management-stormpath-spring-boot.html\",\"name\":\"OAuth 2.0 Token Management with Stormpath and Spring Boot - Java Code Geeks\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2016\\\/11\\\/oauth-2-0-token-management-stormpath-spring-boot.html#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2016\\\/11\\\/oauth-2-0-token-management-stormpath-spring-boot.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/spring-logo.jpg\",\"datePublished\":\"2016-11-14T08:02:10+00:00\",\"dateModified\":\"2016-11-22T06:30:38+00:00\",\"description\":\"Building Identity Management, including authentication and authorization? Try Stormpath! Our REST API and robust Java SDK support can eliminate your\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2016\\\/11\\\/oauth-2-0-token-management-stormpath-spring-boot.html#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2016\\\/11\\\/oauth-2-0-token-management-stormpath-spring-boot.html\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2016\\\/11\\\/oauth-2-0-token-management-stormpath-spring-boot.html#primaryimage\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/spring-logo.jpg\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/spring-logo.jpg\",\"width\":150,\"height\":150,\"caption\":\"spring-interview-questions-answers\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2016\\\/11\\\/oauth-2-0-token-management-stormpath-spring-boot.html#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Enterprise Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\\\/enterprise-java\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"OAuth 2.0 Token Management with Stormpath and Spring Boot\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"name\":\"Java Code Geeks\",\"description\":\"Java Developers Resource Center\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"alternateName\":\"JCG\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.javacodegeeks.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/javacodegeeks\",\"https:\\\/\\\/x.com\\\/javacodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/fd211fe0d3a9791d30dd0ca5276d9660\",\"name\":\"Micah Silverman\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/fdd31b256ed406e9651be5c9f709a208535846dc978cc1b1211f9ca2473709de?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/fdd31b256ed406e9651be5c9f709a208535846dc978cc1b1211f9ca2473709de?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/fdd31b256ed406e9651be5c9f709a208535846dc978cc1b1211f9ca2473709de?s=96&d=mm&r=g\",\"caption\":\"Micah Silverman\"},\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/author\\\/micah-silverman\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"OAuth 2.0 Token Management with Stormpath and Spring Boot - Java Code Geeks","description":"Building Identity Management, including authentication and authorization? Try Stormpath! Our REST API and robust Java SDK support can eliminate your","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.javacodegeeks.com\/2016\/11\/oauth-2-0-token-management-stormpath-spring-boot.html","og_locale":"en_US","og_type":"article","og_title":"OAuth 2.0 Token Management with Stormpath and Spring Boot - Java Code Geeks","og_description":"Building Identity Management, including authentication and authorization? Try Stormpath! Our REST API and robust Java SDK support can eliminate your","og_url":"https:\/\/www.javacodegeeks.com\/2016\/11\/oauth-2-0-token-management-stormpath-spring-boot.html","og_site_name":"Java Code Geeks","article_publisher":"https:\/\/www.facebook.com\/javacodegeeks","article_published_time":"2016-11-14T08:02:10+00:00","article_modified_time":"2016-11-22T06:30:38+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","type":"image\/jpeg"}],"author":"Micah Silverman","twitter_card":"summary_large_image","twitter_creator":"@javacodegeeks","twitter_site":"@javacodegeeks","twitter_misc":{"Written by":"Micah Silverman","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.javacodegeeks.com\/2016\/11\/oauth-2-0-token-management-stormpath-spring-boot.html#article","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/2016\/11\/oauth-2-0-token-management-stormpath-spring-boot.html"},"author":{"name":"Micah Silverman","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/fd211fe0d3a9791d30dd0ca5276d9660"},"headline":"OAuth 2.0 Token Management with Stormpath and Spring Boot","datePublished":"2016-11-14T08:02:10+00:00","dateModified":"2016-11-22T06:30:38+00:00","mainEntityOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2016\/11\/oauth-2-0-token-management-stormpath-spring-boot.html"},"wordCount":1919,"commentCount":0,"publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2016\/11\/oauth-2-0-token-management-stormpath-spring-boot.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","keywords":["Spring","Spring Boot"],"articleSection":["Enterprise Java"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.javacodegeeks.com\/2016\/11\/oauth-2-0-token-management-stormpath-spring-boot.html#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.javacodegeeks.com\/2016\/11\/oauth-2-0-token-management-stormpath-spring-boot.html","url":"https:\/\/www.javacodegeeks.com\/2016\/11\/oauth-2-0-token-management-stormpath-spring-boot.html","name":"OAuth 2.0 Token Management with Stormpath and Spring Boot - Java Code Geeks","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2016\/11\/oauth-2-0-token-management-stormpath-spring-boot.html#primaryimage"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2016\/11\/oauth-2-0-token-management-stormpath-spring-boot.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","datePublished":"2016-11-14T08:02:10+00:00","dateModified":"2016-11-22T06:30:38+00:00","description":"Building Identity Management, including authentication and authorization? Try Stormpath! Our REST API and robust Java SDK support can eliminate your","breadcrumb":{"@id":"https:\/\/www.javacodegeeks.com\/2016\/11\/oauth-2-0-token-management-stormpath-spring-boot.html#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.javacodegeeks.com\/2016\/11\/oauth-2-0-token-management-stormpath-spring-boot.html"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/2016\/11\/oauth-2-0-token-management-stormpath-spring-boot.html#primaryimage","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","width":150,"height":150,"caption":"spring-interview-questions-answers"},{"@type":"BreadcrumbList","@id":"https:\/\/www.javacodegeeks.com\/2016\/11\/oauth-2-0-token-management-stormpath-spring-boot.html#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.javacodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"Java","item":"https:\/\/www.javacodegeeks.com\/category\/java"},{"@type":"ListItem","position":3,"name":"Enterprise Java","item":"https:\/\/www.javacodegeeks.com\/category\/java\/enterprise-java"},{"@type":"ListItem","position":4,"name":"OAuth 2.0 Token Management with Stormpath and Spring Boot"}]},{"@type":"WebSite","@id":"https:\/\/www.javacodegeeks.com\/#website","url":"https:\/\/www.javacodegeeks.com\/","name":"Java Code Geeks","description":"Java Developers Resource Center","publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"alternateName":"JCG","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.javacodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.javacodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.javacodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/javacodegeeks","https:\/\/x.com\/javacodegeeks"]},{"@type":"Person","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/fd211fe0d3a9791d30dd0ca5276d9660","name":"Micah Silverman","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/fdd31b256ed406e9651be5c9f709a208535846dc978cc1b1211f9ca2473709de?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/fdd31b256ed406e9651be5c9f709a208535846dc978cc1b1211f9ca2473709de?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/fdd31b256ed406e9651be5c9f709a208535846dc978cc1b1211f9ca2473709de?s=96&d=mm&r=g","caption":"Micah Silverman"},"url":"https:\/\/www.javacodegeeks.com\/author\/micah-silverman"}]}},"_links":{"self":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/61622","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/users\/1062"}],"replies":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/comments?post=61622"}],"version-history":[{"count":0,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/61622\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media\/240"}],"wp:attachment":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media?parent=61622"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/categories?post=61622"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/tags?post=61622"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}