{"id":10135,"date":"2016-09-08T02:39:29","date_gmt":"2016-09-07T17:39:29","guid":{"rendered":"https:\/\/jirak.net\/wp\/authenticating-users-to-existing-applications-with-openid-connect-and-nginx-plus\/"},"modified":"2016-09-08T03:34:50","modified_gmt":"2016-09-07T18:34:50","slug":"authenticating-users-to-existing-applications-with-openid-connect-and-nginx-plus","status":"publish","type":"post","link":"https:\/\/jirak.net\/wp\/authenticating-users-to-existing-applications-with-openid-connect-and-nginx-plus\/","title":{"rendered":"Authenticating Users to Existing Applications with OpenID\u00a0Connect and NGINX\u00a0Plus"},"content":{"rendered":"<p>Authenticating Users to Existing Applications with OpenID\u00a0Connect and NGINX\u00a0Plus<br \/>\n<img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/jirak.net\/wp\/wp-content\/uploads\/2016\/09\/jwt-openid-connect-sso-flow.png\" width=\"623\" height=\"496\"><\/p>\n<h3><em>Using JWT support to provide SSO for existing applications<\/em><\/h3>\n<p>OAuth&nbsp;2.0 has done much to transform the flexibility and user experience of authenticating to websites and applications. But despite the name, the <a target=\"_blank\" href=\"https:\/\/tools.ietf.org\/html\/rfc6749?utm_source=authenticating-users-existing-applications-openid-connect-nginx-plus&amp;utm_medium=blog\">OAuth&nbsp;2.0 specification<\/a> says very little about verifying end&#8209;user identity and nothing about single sign&#8209;on (SSO). That\u2019s where <a target=\"_blank\" href=\"http:\/\/openid.net\/connect\/?utm_source=authenticating-users-existing-applications-openid-connect-nginx-plus&amp;utm_medium=blog\">OpenID&nbsp;Connect<\/a> comes in&nbsp;&ndash; it is essentially the missing piece that carries identity information in OAuth&nbsp;2.0 access tokens.<\/p>\n<p>OpenID&nbsp;Connect identity tokens comply with the <a target=\"_blank\" href=\"https:\/\/tools.ietf.org\/html\/rfc7519?utm_source=authenticating-users-existing-applications-openid-connect-nginx-plus&amp;utm_medium=blog\">JSON Web Token (JWT) specification<\/a>. JWT (pronounced \u201cjot\u201d) tokens  are compact, easy to pass around, and provide a common core schema for describing identity information. The great thing about JWTs is that they can be applied to almost any identity use case, from authenticating API clients to providing SSO for enterprise applications. In fact, many organizations that use Google&nbsp;Apps can <a target=\"_blank\" href=\"https:\/\/cloud.google.com\/docs\/enterprise\/best-practices-for-enterprise-organizations?utm_source=authenticating-users-existing-applications-openid-connect-nginx-plus&amp;utm_medium=blog#consider_using_google_as_an_identity_provider_for_other_services\">utilize Google as the identity provider to provide SSO to their enterprise applications<\/a>. That said, the use of OpenID&nbsp;Connect and JWTs does not prevent them being used to authenticate to, or provide SSO for, existing web applications.<\/p>\n<p>NGINX&nbsp;Plus&nbsp;R10 and later includes native JWT support, enabling NGINX&nbsp;Plus to validate tokens and decorate upstream requests with the identity of the authenticated user in a way that the application can easily consume. In this blog post we demonstrate how to use the native JWT support in NGINX&nbsp;Plus to enable SSO for existing applications without any changes required to the applications themselves. We&#8217;re using Google as the identity provider and a simple website to represent the application. The end&#8209;to&#8209;end flow looks like this:<\/p>\n<figure id=\"attachment_45680\" style=\"width: 623px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/assets.wp.nginx.com\/wp-content\/uploads\/2016\/09\/jwt-openid-connect-sso-flow.png\" alt=\"Diagram depicting the processing flow as NGINX Plus validates user identity using OAuth 2.0 and OpenID Connect with Google\" width=\"623\" height=\"496\" class=\"size-full wp-image-45680\" \/><figcaption class=\"wp-caption-text\">NGINX&nbsp;Plus validates user identity using OAuth 2.0 and OpenID Connect with Google<\/figcaption><\/figure>\n<h2 id=\"openid-connect-enable\">Enabling OpenID&nbsp;Connect for Your Web Application<\/h2>\n<p>Our example has two components: the NGINX&nbsp;Plus configuration and the HTML login page.<\/p>\n<h3>NGINX&nbsp;Plus Configuration<\/h3>\n<p>The NGINX&nbsp;Plus configuration for validating JWTs is very simple.<\/p>\n<pre><code class=\"config\">server {<br \/>\n    listen 80;<br \/>\n    root \/var\/www\/public_html;<\/p>\n<p>    location \/private\/ {<br \/>\n        auth_jwt \"Google account\" token=$cookie_auth_token;<br \/>\n        auth_jwt_key_file \/etc\/nginx\/google_certs.jwk;<br \/>\n    }<br \/>\n}<\/pre>\n<p><\/code><\/p>\n<p>The <code>location<\/code> block specifies that any requests to URLs beginning with <strong>\/private\/<\/strong> must be authenticated. The <a target=\"_blank\" href=\"http:\/\/nginx.org\/en\/docs\/http\/ngx_http_auth_jwt_module.html?utm_source=authenticating-users-existing-applications-openid-connect-nginx-plus&amp;utm_medium=blog#auth_jwt\"><code>auth_jwt<\/code><\/a> directive defines the authentication realm that will be returned (along with a <code>401<\/code>) if authentication is unsuccessful, and where in the request NGINX&nbsp;Plus can find the JWT. In this case it expects to find the token in a cookie named <strong>auth_token<\/strong>. By default, NGINX&nbsp;Plus expects clients to present the JWT as a <a target=\"_blank\" href=\"https:\/\/tools.ietf.org\/html\/rfc6750?utm_source=authenticating-users-existing-applications-openid-connect-nginx-plus&amp;utm_medium=blog\"><em>Bearer&nbsp;Token<\/em><\/a>, using the <code>Authorization<\/code> header as is common with <a href=\"https:\/\/www.nginx.com\/blog\/authenticating-api-clients-jwt-nginx-plus\/?utm_source=authenticating-users-existing-applications-openid-connect-nginx-plus&amp;utm_medium=blog\">AJAX applications and API clients<\/a>, but it can also obtain the JWT from other HTTP headers, query string arguments, or a cookie as in this example.<\/p>\n<p>The <a target=\"_blank\" href=\"http:\/\/nginx.org\/en\/docs\/http\/ngx_http_auth_jwt_module.html?utm_source=authenticating-users-existing-applications-openid-connect-nginx-plus&amp;utm_medium=blog#auth_jwt_key_file\"><code>auth_jwt_key_file<\/code><\/a> directive tells NGINX how to validate the signature element of the JWT. Signature validation ensures that the JWT was issued by Google and has not been modified since. Google <a target=\"_blank\" href=\"https:\/\/www.googleapis.com\/oauth2\/v3\/certs?utm_source=authenticating-users-existing-applications-openid-connect-nginx-plus&amp;utm_medium=blog\">publishes its public keys<\/a> and refreshes them regularly. To maintain an up&#8209;to&#8209;date set of keys, use <code>cron(8)<\/code> to fetch them hourly, as in this sample <code>crontab<\/code> entry.<\/p>\n<pre><code class=\"config\">0 * * * * wget https:\/\/www.googleapis.com\/oauth2\/v3\/certs -O \/etc\/nginx\/google_certs.jwk<\/pre>\n<p><\/code><\/p>\n<h3>HTML-Based Login Page<\/h3>\n<p>To keep this example simple and straightforward, we aren&#8217;t building an entire application. Instead we&#8217;re using the following basic HTML to create a login page. The HTML file is called <strong>\/var\/www\/public_html\/index.html<\/strong> (this matches the <code>root<\/code> path we defined in the NGINX&nbsp;Plus configuration).<\/p>\n<pre class=\"scrollable jq_custom_scroll_dark\"><code class=\"config\">&lt;html&gt;<br \/>\n&lt;head&gt;<br \/>\n    &lt;meta http-equiv=\"cache-control\" content=\"no-cache\" \/&gt;<br \/>\n    &lt;meta http-equiv=\"expires\" content=\"0\" \/&gt;<br \/>\n    &lt;title&gt;NGINX OpenID Connect demo&lt;\/title&gt;<br \/>\n    &lt;script src=\"https:\/\/apis.google.com\/js\/platform.js\" async defer&gt;&lt;\/script&gt;<br \/>\n    &lt;meta name=\"google-signin-scope\" content=\"profile email\"&gt;<br \/>\n    &lt;meta name=\"google-signin-client_id\"<br \/>\n          content=\"<span style=\"color:#f2a900;font-weight:bold\"><em>client-ID<\/em>.apps.googleusercontent.com<\/strong><\/span>\"&gt;<br \/>\n    <span style=\"color:#f2a900;font-weight:bold\">&lt;script src=\"https\/\/tools.ietf.org\/js.cookie.js\"&gt;&lt;\/script&gt;<\/strong><\/span><br \/>\n&lt;\/head&gt;<br \/>\n&lt;body&gt;<br \/>\n    &lt;h2&gt;NGINX OpenID Connect demo&lt;\/h2&gt;<br \/>\n    &lt;hr\/&gt;<br \/>\n    &lt;h3&gt;Login with a Google account then visit the &lt;a href=\"\/private\/\"&gt;private area&lt;\/a&gt;.&lt;\/h3&gt;<br \/>\n    &lt;table&gt;&lt;tr&gt;&lt;td&gt;<br \/>\n    &lt;div class=\"g-signin2\" data-onsuccess=\"onSignIn\" data-theme=\"dark\"&gt;&lt;\/div&gt;&lt;\/td&gt;<br \/>\n    &lt;script&gt;<br \/>\n      function onSignIn(googleUser) {<br \/>\n        var profile = googleUser.getBasicProfile();<br \/>\n        Cookies.set('auth_token', googleUser.getAuthResponse().id_token);<br \/>\n        document.getElementById('google_signout').innerHTML = '&lt;a href=\"#\" onclick=\"signOut();\"&gt;&lt;img src=\"' + profile.getImageUrl() + '\" width=32 height=32&gt;Sign out&lt;\/a&gt;';<br \/>\n      };<br \/>\n      function signOut() {<br \/>\n        var auth2 = gapi.auth2.getAuthInstance();<br \/>\n        auth2.signOut().then(function () {<br \/>\n          Cookies.remove('auth_token');<br \/>\n          document.getElementById('google_signout').innerHTML = '';<br \/>\n        });<br \/>\n      }<br \/>\n    &lt;\/script&gt;<br \/>\n    &lt;td&gt;&lt;div id=\"google_signout\"&gt;&lt;\/div&gt;&lt;\/td&gt;<br \/>\n    &lt;\/tr&gt;&lt;\/table&gt;<br \/>\n    &lt;hr\/&gt;<br \/>\n&lt;\/body&gt;<br \/>\n&lt;\/html&gt;<\/pre>\n<p><\/code><\/p>\n<p>We&#8217;ve highlighted two key dependencies in the <code>&lt;head&gt;<\/code> block. <\/p>\n<ul>\n<li><code>&lt;meta&nbsp;name=\"google&#8209;signin&#8209;client_id\"&gt;<\/code> tag&nbsp;&ndash; We are using <a target=\"_blank\" href=\"https:\/\/developers.google.com\/+\/web\/api\/javascript?utm_source=authenticating-users-existing-applications-openid-connect-nginx-plus&amp;utm_medium=blog\">Google\u2019s OAuth&nbsp;2.0 JavaScript API<\/a> to perform the OAuth&nbsp;2.0 end&#8209;user consent and authentication process. This is what gives us the login button and can detect whether we are logged in or not. In order for our website to be authenticated by Google, we need to create an OAuth&nbsp;2.0 client ID and provide that as the <code>content<\/code> attribute to this tag, replacing the <strong><em><code>client-ID<\/code><\/em><\/strong> placeholder. For instructions on creating a new OAuth&nbsp;2.0 client ID, see the <a href=\"?utm_source=authenticating-users-existing-applications-openid-connect-nginx-plus&amp;utm_medium=blog#appendix\">Appendix<\/a> at the bottom of this article.<\/li>\n<li><code>&lt;script&nbsp;src=\"https\/\/tools.ietf.org\/js.cookie.js\"&gt;<\/code> tag&nbsp;&ndash; We need a cookie parser that can extract the identity token from the OAuth&nbsp;2.0 access token and create a cookie to be sent to the website. The line <code>Cookies.set<\/code> accomplishes this, using the <a target=\"_blank\" href=\"https:\/\/github.com\/js-cookie\/js-cookie\/blob\/v2.1.2\/src\/js.cookie.js?utm_source=authenticating-users-existing-applications-openid-connect-nginx-plus&amp;utm_medium=blog\">JavaScript Cookie<\/a> library, which is included with the this tag.<\/li>\n<\/ul>\n<p>With these pieces in place we now have a public homepage with Google\u2019s login mechanism and a private area protected by NGINX&nbsp;Plus. Note that we didn\u2019t create any content for our private area so a <code>404<\/code> error is to be expected when we try to access it.<\/p>\n<h2>Further Reading<\/h2>\n<p>For details about advanced JWT functionality, see <a href=\"https:\/\/www.nginx.com\/blog\/authenticating-api-clients-jwt-nginx-plus\/?utm_source=authenticating-users-existing-applications-openid-connect-nginx-plus&amp;utm_medium=blog\">Authenticating API Clients with JWT and NGINX&nbsp;Plus<\/a>. It explains how to proxy authenticated requests with user identity information obtained from the JWT, log JWT claims, and support multiple identity providers.<\/p>\n<p>To explore the native JWT support in NGINX&nbsp;Plus&nbsp;R10 and later for yourself, start your <span><a href=\"https:\/\/www.nginx.com\/free-trial-request?utm_source=authenticating-users-existing-applications-openid-connect-nginx-plus&amp;utm_medium=blog\">free 30&#8209;day trial<\/a><\/span> today or <a href=\"?utm_source=authenticating-users-existing-applications-openid-connect-nginx-plus&amp;utm_medium=blog#contact-us\">contact&nbsp;us<\/a> for a live demo.<\/p>\n<hr \/>\n<h2 id=\"appendix\">Appendix&nbsp;&ndash; Creating a Google OAuth&nbsp;2.0 Client ID<\/h2>\n<ol>\n<li>\n<p>Access the Google Developer&#8217;s Console at <a target=\"_blank\" href=\"https:\/\/console.developers.google.com\/start?utm_source=authenticating-users-existing-applications-openid-connect-nginx-plus&amp;utm_medium=blog\">https:\/\/console.developers.google.com\/start<\/a>.<\/p>\n<p>The page that opens depends on your history with Google APIs. You might have to create an account, accept terms of use, and perform other steps not shown in these instructions. <\/p>\n<p>Ultimately you need to access the <a target=\"_blank\" href=\"https:\/\/console.developers.google.com\/apis\/dashboard?utm_source=authenticating-users-existing-applications-openid-connect-nginx-plus&amp;utm_medium=blog\">Google APIs dashboard<\/a>. The following screenshot shows the upper left corner of the dashboard. Click the word to the right of the <strong>Google&nbsp;APIs<\/strong> logo (if you have previously created a project, its name might appear instead of the word <strong>Project<\/strong>). Select <strong>Create&nbsp;project<\/strong>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/assets.wp.nginx.com\/wp-content\/uploads\/2016\/09\/google-oauth2.0-client-id-create-project.png\" alt=\"When creating a Google OAuth 2.0 client ID, select 'Create project' from the drop-down menu next to the Google APIs logo in the upper left corner of the API Manager dashboard.\" width=\"355\" height=\"136\" class=\"aligncenter size-full wp-image-45683\" \/>\n<\/li>\n<li>\n<p>Create a new project. Here our new project is called <strong>NGINX&nbsp;OpenID<\/strong>. After you click the <strong>Create<\/strong> button, it can take several seconds before a notification appears indicating your project has been created.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/assets.wp.nginx.com\/wp-content\/uploads\/2016\/09\/google-oauth2.0-client-id-new-project.png\" alt=\"When creating a Google OAuth 2.0 client ID, specify a name for your new project.\" width=\"500\" height=\"227\" class=\"aligncenter size-full wp-image-45695\" \/>\n<\/li>\n<li>\n<p>Enable the Google+ API for your project. It provides OAuth 2.0 authentication and identity services.<\/p>\n<p>(If the API Manager dashboard doesn&#8217;t already appear in the main part of the window, click <strong>Dashboard<\/strong> in the navigation area on the left of the screen.)<\/p>\n<p>The first step in enabling the Google+ API is to click the <strong>ENABLE&nbsp;API<\/strong> button.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/assets.wp.nginx.com\/wp-content\/uploads\/2016\/09\/google-oauth2.0-client-id-enable-api.png\" alt=\"When creating a Google OAuth 2.0 client ID, while on the API Manager Dashboard screen click the ENABLE API button.\" width=\"581\" height=\"258\" class=\"aligncenter size-full wp-image-45685\" \/>\n<\/li>\n<li>\n<p>Click <strong>Google+&nbsp;API<\/strong> (in the <strong>Social&nbsp;APIs<\/strong> section).<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/assets.wp.nginx.com\/wp-content\/uploads\/2016\/09\/google-oauth2.0-client-id-select-api.png\" alt=\"When creating a Google OAuth 2.0 client ID, select the Google+ API from the list of 'Social APIs' on the Library screen of the API Manager.\" width=\"848\" height=\"554\" class=\"aligncenter size-full wp-image-45689\" \/>\n<\/li>\n<li>\n<p>Click the <strong>ENABLE<\/strong> button.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/assets.wp.nginx.com\/wp-content\/uploads\/2016\/09\/google-oauth2.0-client-id-google-api-enable.png\" alt=\"When creating a Google OAuth 2.0 client ID, after having selected the Google+ API, click the 'Enable' button.\" width=\"919\" height=\"359\" class=\"aligncenter size-full wp-image-45686\" \/>\n<\/li>\n<li>\n<p>To create credentials for your project, click <strong>Credentials<\/strong> in the navigation area on the left of the screen, then click the <strong>Create&nbsp;Credentials<\/strong> button.<\/p>\n<p>Select <strong>OAuth&nbsp;client&nbsp;ID<\/strong> on the drop&#8209;down menu.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/assets.wp.nginx.com\/wp-content\/uploads\/2016\/09\/google-oauth2.0-client-id-create-credentials.png\" alt=\"When creating a Google OAuth 2.0 client ID, select 'OAuth client ID' as the type of credential to create.\" width=\"449\" height=\"459\" class=\"aligncenter size-full wp-image-45682\" \/>\n<\/li>\n<li>\n<p>Select the <strong>Web&nbsp;application<\/strong> radio button. In the <strong>Authorized&nbsp;JavaScript&nbsp;origins<\/strong> field, specify the URL for the host where NGINX&nbsp;Plus is installed and the port number you specified as the parameter to the <code>listen<\/code> directive in <a href=\"?utm_source=authenticating-users-existing-applications-openid-connect-nginx-plus&amp;utm_medium=blog#openid-connect-enable\">Enabling OpenID&nbsp;Connect for Your Web Application<\/a> (for example, <strong>mydomain.example.com:80<\/strong>). This example uses localhost but your entry needs to be the hostname and port of the actual NGINX&nbsp;Plus instance.<\/p>\n<p>Click the <strong>Create<\/strong> button (you might need to click it more than once to make the creation process start).<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/assets.wp.nginx.com\/wp-content\/uploads\/2016\/09\/google-oauth2.0-client-id-create.png\" alt=\"When creating a Google OAuth 2.0 client ID, specify the 'Web application' application type and specify the URL for your NGINX Plus host as an 'Authorized JavaScript origin'.;\" width=\"892\" height=\"694\" class=\"aligncenter size-full wp-image-45684\" \/>\n<\/li>\n<li>\n<p>The <strong>OAuth&nbsp;client<\/strong> window pops up to report your client ID and client secret. Copy the client ID to the <code>content<\/code> attribute of the <code>&lt;meta name=\"google-signin-client_id\"&gt;<\/code> tag in your app (replacing the highlighted <strong><em><code>client-ID<\/code><\/em><\/strong> placeholder shown above). You do not need the client secret.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/assets.wp.nginx.com\/wp-content\/uploads\/2016\/09\/google-oauth2.0-client-id-secret.png\" alt=\"When you have successfully created a Google OAuth 2.0 client ID, it appears in the 'OAuth client' window along with the client secret.\" width=\"553\" height=\"224\" class=\"aligncenter size-full wp-image-45687\" \/>\n<\/li>\n<li>\n<p>On main <strong>Credentials<\/strong> screen, click <strong>OAuth&nbsp;consent&nbsp;screen<\/strong>. Provide your email address and a product name (all other fields are optional).<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/assets.wp.nginx.com\/wp-content\/uploads\/2016\/09\/google-oauth2.0-client-id-consent-screen.png\" alt=\"When creating a Google OAuth 2.0 client ID, specify your email address and the product name on the 'OAuth consent screen' under API Manager &gt; Credentials.\" width=\"728\" height=\"296\" class=\"aligncenter size-full wp-image-45681\" \/>\n<\/li>\n<\/ol>\n<p>To explore the native JWT support in NGINX&nbsp;Plus&nbsp;R10 and later for yourself, start your <span><a href=\"https:\/\/www.nginx.com\/free-trial-request?utm_source=authenticating-users-existing-applications-openid-connect-nginx-plus&amp;utm_medium=blog\">free 30&#8209;day trial<\/a><\/span> today or <a href=\"?utm_source=authenticating-users-existing-applications-openid-connect-nginx-plus&amp;utm_medium=blog#contact-us\">contact&nbsp;us<\/a> for a live demo.<\/p>\n<p>The post <a rel=\"nofollow\" href=\"https:\/\/www.nginx.com\/blog\/authenticating-users-existing-applications-openid-connect-nginx-plus\/\">Authenticating Users to Existing Applications with OpenID&nbsp;Connect and NGINX&nbsp;Plus<\/a> appeared first on <a rel=\"nofollow\" href=\"https:\/\/www.nginx.com\">NGINX<\/a>.<\/p>\n<p>Source: <a href=\"https:\/\/www.nginx.com\/blog\/authenticating-users-existing-applications-openid-connect-nginx-plus\/\" target=\"_blank\">Authenticating Users to Existing Applications with OpenID\u00a0Connect and NGINX\u00a0Plus<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div class=\"mh-excerpt\"><p>Authenticating Users to Existing Applications with OpenID\u00a0Connect and NGINX\u00a0Plus Using JWT support to provide SSO for existing applications OAuth&nbsp;2.0 has done much to transform the flexibility and user experience of authenticating to websites and applications. But despite the name, the OAuth&nbsp;2.0 specification says very little about verifying end&#8209;user identity and nothing about single sign&#8209;on (SSO). That\u2019s where OpenID&nbsp;Connect comes in&nbsp;&ndash; it is essentially the missing piece that carries identity information in OAuth&nbsp;2.0 access tokens. OpenID&nbsp;Connect identity tokens comply with the JSON Web Token (JWT) specification. JWT (pronounced \u201cjot\u201d) tokens are compact, easy to pass around, and provide a common core schema for describing identity information. The great thing about JWTs is that they can be applied to almost any identity use case, from authenticating API clients to providing SSO for enterprise applications. In fact, many organizations that use Google&nbsp;Apps can <a class=\"mh-excerpt-more\" href=\"https:\/\/jirak.net\/wp\/authenticating-users-to-existing-applications-with-openid-connect-and-nginx-plus\/\" title=\"Authenticating Users to Existing Applications with OpenID\u00a0Connect and NGINX\u00a0Plus\">[ more&#8230; ]<\/a><\/p>\n<\/div>","protected":false},"author":1,"featured_media":10136,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[169],"tags":[652],"class_list":["post-10135","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-news","tag-nginx"],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/posts\/10135","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/comments?post=10135"}],"version-history":[{"count":1,"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/posts\/10135\/revisions"}],"predecessor-version":[{"id":10137,"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/posts\/10135\/revisions\/10137"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/media\/10136"}],"wp:attachment":[{"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/media?parent=10135"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/categories?post=10135"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/tags?post=10135"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}