{"id":26146,"date":"2024-02-29T15:40:07","date_gmt":"2024-02-29T14:40:07","guid":{"rendered":"https:\/\/blog.mi.hdm-stuttgart.de\/?p=26146"},"modified":"2024-02-29T18:03:34","modified_gmt":"2024-02-29T17:03:34","slug":"using-keycloak-as-iam-for-our-hosting-provider-service","status":"publish","type":"post","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2024\/02\/29\/using-keycloak-as-iam-for-our-hosting-provider-service\/","title":{"rendered":"Using Keycloak as IAM for our hosting provider service"},"content":{"rendered":"\n<p>A variety of today&#8217;s applications require careful handling of user data. However, especially in student projects, due to time constraints or the focus of the project, there is a tendency to neglect or only superficially implement authentication and handling of user data.<\/p>\n\n\n\n<p>In the context of our project for the lecture &#8216;System Engineering and Management&#8217; we have decided to create a hosting provider. Users should be able to book and start Docker container instances via a CLI application. For this project, it was important for us to integrate comprehensive Identity and Access Management (IAM) for our users.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What is Keycloak!?<\/h2>\n\n\n\n<p>Keycloak is an open-source software for identity and access management developed by Red Hat. It provides a comprehensive solution for authentication, authorization, and user management for web applications and services. Essentially, Keycloak functions as a Single Sign-On (SSO) solution, allowing users to authenticate once and then access multiple applications and services without needing to log in again.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Why did we decide to use Keycloak for IAM?<\/h2>\n\n\n\n<p>One of the main reasons why we chose Keycloak over other identity and access management systems is the fact that Keycloak is open-source and therefore free of cost. Since we already operate our own server for hosting the Docker instances, we can also host our Keycloak server on it. Another reason is the huge amount of features offered by Keycloak, which we may not fully utilize at the moment but could become relevant in future (larger) projects. Therefore, we wanted to gain experience with Keycloak already at this stage. Given that Keycloak is maintained by Red Hat and not just a community project, we have great confidence in the software.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How do we utilize Keycloak in our application?<\/h2>\n\n\n\n<p><br>Since Keycloak provides a pre-built web interface for login, registration, and logout, we have decided to utilize this web-based OpenID Connect authentication flow. The concept behind it is as follows:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>The user wants to log in or register via CLI. To do this, a local callback web server is started, and the browser is automatically opened with the corresponding Keycloak interface.<br><\/li>\n\n\n\n<li>After successful login or registration on the Keycloak web interface, the browser is redirected to the local callback server. An authentication code is passed as a URL parameter.<br><\/li>\n\n\n\n<li>The CLI or the callback server can request a Token Exchange using the authentication code. The authentication code is exchanged for a JWT Token Set. This typically consists of an Access Token, used for API requests against the backend, and a Refresh Token, which can be used when the Access Token expires to request a new JWT Token Set from Keycloak.<br><\/li>\n\n\n\n<li>The CLI stores the Token Set locally on the device for future use.<br><\/li>\n\n\n\n<li>When a request to the backend is made, the tokens are read again. If no tokens are present, it means the user is not logged in. The backend uses these tokens to identify the user.<br><\/li>\n\n\n\n<li>In the case of an expired token, the CLI can use the Refresh Token to obtain a new Token Set from Keycloak and retry the request to the backend.<\/li>\n<\/ol>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full wp-duotone-unset-1\"><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2024\/02\/stmk_diagrams_en.png\"><img loading=\"lazy\" decoding=\"async\" width=\"355\" height=\"516\" data-attachment-id=\"26150\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2024\/02\/29\/using-keycloak-as-iam-for-our-hosting-provider-service\/stmk_diagrams_en\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2024\/02\/stmk_diagrams_en.png\" data-orig-size=\"355,516\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"stmk_diagrams_en\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2024\/02\/stmk_diagrams_en.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2024\/02\/stmk_diagrams_en.png\" alt=\"The authentication flow for our CLI using Keycloak\" class=\"wp-image-26150\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2024\/02\/stmk_diagrams_en.png 355w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2024\/02\/stmk_diagrams_en-206x300.png 206w\" sizes=\"auto, (max-width: 355px) 100vw, 355px\" \/><\/a><figcaption class=\"wp-element-caption\">Fig. 1: The authentication flow for our CLI using Keycloak<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Using Keycloaks SPI to listen to events<\/h2>\n\n\n\n<p>In the implemented hosting provider application, user-related data such as the username, email address, and password are stored in Keycloak. Additionally, the application includes a simple payment model: Each user has a balance that can be topped up and is used to bill the services used by the hosting provider. These user-specific balance information is not stored in Keycloak but in a separate Amazon DynamoDB.<br><br>A user is able to self-register using the keycloak web interface. Also there might be the case where a user contacts us in order to get his account deleted. In this context, depending on the event performed, it was necessary to create or remove a corresponding balance instance for the respective user in DynamoDB. The central challenge is to ensure that the data in both Keycloak and the standalone Amazon DynamoDB are consistent and data integrity is maintained.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How can we fix it?<\/h3>\n\n\n\n<p><strong>Approach 1<\/strong>: One solution could be the interval-based checking of the data in Keycloak and the separate database to detect and correct inconsistencies. This approach has two disadvantages though: Firstly, the update between Keycloak and the database does not occur in real-time but only at predefined intervals. Furthermore, the data synchronization between Keycloak and the database leads to long-term performance issues if the application is expected to be used by many users.<\/p>\n\n\n\n<p><strong>Approach 2<\/strong>: In addition to the interval-based solution, there is also a way to react in real-time to events such as the creation or deletion of a user. Keycloak provides Service Provider Interfaces (SPIs) which serve as interfaces for extensions or customizations.<\/p>\n\n\n\n<p>Regarding our hosting provider service, an Event Listener SPI is used to react to specific Keycloak events and perform logging. This approach circumvents the performance problem of the first approach and also offers a real-time solution instead of an interval-based one. This results in the following flow:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>A new user is created or deleted in Keycloak manually or via the CLI application.<\/li>\n\n\n\n<li>A SPI event is triggered, which is captured by an event listener.<\/li>\n\n\n\n<li>These events are transmitted to the backend via webhooks.<\/li>\n\n\n\n<li>The backend responds accordingly to the events and creates or deletes a balance instance in the database for the respective user.<\/li>\n<\/ol>\n\n\n\n<figure class=\"wp-block-image aligncenter size-large is-resized\"><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2024\/02\/Bildschirmfoto-2024-02-29-um-16.16.17.png\"><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"26169\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2024\/02\/29\/using-keycloak-as-iam-for-our-hosting-provider-service\/bildschirmfoto-2024-02-29-um-16-16-17\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2024\/02\/Bildschirmfoto-2024-02-29-um-16.16.17.png\" data-orig-size=\"1446,616\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"Bildschirmfoto-2024-02-29-um-16.16.17\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2024\/02\/Bildschirmfoto-2024-02-29-um-16.16.17-1024x436.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2024\/02\/Bildschirmfoto-2024-02-29-um-16.16.17-1024x436.png\" alt=\"Event Listener SPI for Keycloak\" class=\"wp-image-26169\" width=\"512\" height=\"218\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2024\/02\/Bildschirmfoto-2024-02-29-um-16.16.17-1024x436.png 1024w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2024\/02\/Bildschirmfoto-2024-02-29-um-16.16.17-300x128.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2024\/02\/Bildschirmfoto-2024-02-29-um-16.16.17-768x327.png 768w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2024\/02\/Bildschirmfoto-2024-02-29-um-16.16.17.png 1446w\" sizes=\"auto, (max-width: 512px) 100vw, 512px\" \/><\/a><figcaption class=\"wp-element-caption\">Fig. 2: Event Listener SPI for Keycloak<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Learnings and Tips for Reimplementation<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Public Client: <\/strong>When creating the frontend client in the Keycloak Admin interface, the &#8220;Client authentication&#8221; slider under the &#8220;Capability config&#8221; section should be disabled. This makes the Keycloak client accessible to the public, which is necessary or sensible for a frontend, as a secret required for verification against Keycloak cannot be kept secret within the frontend. There is relatively little information available on how to create a public client, as these options have changed over time.<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Protection against Phishing: <\/strong>To secure the client against phishing attempts, Valid Redirect URIs should definitely be set. In our case we used <a href=\"http:\/\/127.0.0.1\/*\">http:\/\/127.0.0.1\/<\/a>* and <a href=\"https:\/\/127.0.0.1\/\">https:\/\/127.0.0.1\/<\/a>* preventing redirection to an external web server via a phishing link, which could intercept the auth code.<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Dynamic Port for the Callback Server: <\/strong>While developing the CLI or the callback server, we noticed that instead of using a static port for the callback server (e.g., 8080), it&#8217;s better to assign a dynamic port. This is not a problem for Keycloak because no port needs to be specified in the Valid Redirect URIs (all ports are valid). It&#8217;s important that the callback server be created (and ideally already started) to be able to provide the redirect URL for the login request.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p class=\"has-medium-font-size\">The integration of Keycloak into our CLI application for launching Docker container instances on our server has proven to be extremely beneficial. By using Keycloak, we were able to implement a robust Identity and Access Management (IAM) system that provides our users with secure and user-friendly authentication without the need to develop our own IAM service, saving us a lot of time. Additionally, by utilizing the Keycloak Event Listener SPI with our hosting provider, we ensure efficient management of user data through real-time synchronization between Keycloak and the separate database. We are confident that our experience with Keycloak will not only benefit us in this project but also in future projects.<\/p>\n\n\n\n<p>Should you have any further questions, we are available through the comment function and welcome feedback and suggestions. Also check out our other blog posts about <a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2024\/02\/29\/why-system-monitoring-is-important-and-how-we-approached-it\/\" title=\"monitoring\">monitoring<\/a>, <a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2024\/02\/29\/combining-zerolog-loki\/\" title=\"\">zero-log and loki hooks for monitoring<\/a> and <a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2024\/02\/29\/terraform-x-go-challenges-when-interacting-with-terraform-through-go\/\" title=\"terraform\">terraform<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Discover how Keycloak can revolutionize your IAM strategy and propel your projects to new heights of security and efficiency.<\/p>\n","protected":false},"author":1192,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1,22,21,651,2,657],"tags":[335,3,216,1015,1016,1014],"ppma_author":[1012,1007,1017],"class_list":["post-26146","post","type-post","status-publish","format-standard","hentry","category-allgemein","category-student-projects","category-system-architecture","category-system-designs","category-system-engineering","category-teaching-and-learning","tag-cli","tag-docker","tag-golang","tag-iam","tag-ihp","tag-keycloak"],"aioseo_notices":[],"jetpack_featured_media_url":"","jetpack-related-posts":[{"id":26160,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2024\/02\/29\/why-system-monitoring-is-important-and-how-we-approached-it\/","url_meta":{"origin":26146,"position":0},"title":"Why system monitoring is important and how we approached it","author":"Michelle Becher","date":"29. February 2024","format":false,"excerpt":"Introduction Imagine building a service that aims to generate as much user traffic as possible to be as profitable as possible. The infrastructure of your service usually includes some kind of backend, a server and other frameworks. One day, something is not working as it should and you can't seem\u2026","rel":"","context":"In &quot;Allgemein&quot;","block_context":{"text":"Allgemein","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/allgemein\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2024\/02\/monitoring.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2024\/02\/monitoring.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2024\/02\/monitoring.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2024\/02\/monitoring.png?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":26197,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2024\/02\/29\/terraform-x-go-challenges-when-interacting-with-terraform-through-go\/","url_meta":{"origin":26146,"position":1},"title":"Terraform x Go: Challenges when interacting with Terraform through Go","author":"Maximilian Tellmann","date":"29. February 2024","format":false,"excerpt":"Introduction goTerra In a recent project, some of my fellow students and I developed a basic hosting provider that allows a user to spin up Docker containers on a remote server, which is realized by using Terraform locally on the server. During this project, we developed a Go-based backend service\u2026","rel":"","context":"In &quot;Allgemein&quot;","block_context":{"text":"Allgemein","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/allgemein\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2024\/02\/Untitled-Project-1024x905.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2024\/02\/Untitled-Project-1024x905.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2024\/02\/Untitled-Project-1024x905.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2024\/02\/Untitled-Project-1024x905.png?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":22151,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2022\/02\/22\/designing-and-implementing-a-scalable-web-application\/","url_meta":{"origin":26146,"position":2},"title":"Designing the framework for a scalable CI\/CD supported web application","author":"Danial Eshete","date":"22. February 2022","format":false,"excerpt":"Documentation of our approaches to the project, our experiences and finally the lessons we learned. The development team approaches the project with little knowledge of cloud services and infrastructure. Furthermore, no one has significant experience with containers and\/or containerized applications. However, the team is well experienced in web development and\u2026","rel":"","context":"In &quot;Allgemein&quot;","block_context":{"text":"Allgemein","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/allgemein\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2022\/02\/Design_Desktop_Logged_In-3-150x150.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2022\/02\/Design_Desktop_Logged_In-3-150x150.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2022\/02\/Design_Desktop_Logged_In-3-150x150.jpg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2022\/02\/Design_Desktop_Logged_In-3-150x150.jpg?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2022\/02\/Design_Desktop_Logged_In-3-150x150.jpg?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2022\/02\/Design_Desktop_Logged_In-3-150x150.jpg?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":26145,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2024\/02\/29\/combining-zerolog-loki\/","url_meta":{"origin":26146,"position":3},"title":"Combining zerolog &amp; Loki","author":"Max Herkenhoff","date":"29. February 2024","format":false,"excerpt":"Publish zerolog events to Loki in just a few lines of code.","rel":"","context":"In &quot;Allgemein&quot;","block_context":{"text":"Allgemein","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/allgemein\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":5313,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2019\/02\/26\/experiences-from-breaking-down-a-monolith-3\/","url_meta":{"origin":26146,"position":4},"title":"Experiences from breaking down a monolith (3)","author":"Marcel Heisler","date":"26. February 2019","format":false,"excerpt":"Written by Verena Barth, Marcel Heisler, Florian Rupp, & Tim Tenckhoff DevOps Code Sharing Building multiple services hold in separated code repositories, we headed the problem of code duplication. Multiple times a piece of code is used twice, for example data models. As the services grow larger, just copying is\u2026","rel":"","context":"In &quot;System Architecture&quot;","block_context":{"text":"System Architecture","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/system-designs\/system-architecture\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/02\/Bild_eingefugt_am_2019-02-26__1_31_PM-2-150x150.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/02\/Bild_eingefugt_am_2019-02-26__1_31_PM-2-150x150.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/02\/Bild_eingefugt_am_2019-02-26__1_31_PM-2-150x150.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/02\/Bild_eingefugt_am_2019-02-26__1_31_PM-2-150x150.png?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":3421,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2018\/03\/28\/take-me-home-project-overview\/","url_meta":{"origin":26146,"position":5},"title":"Take Me Home &#8211; Project Overview","author":"cp054","date":"28. March 2018","format":false,"excerpt":"Related articles:\u00a0\u25baCI\/CD infrastructure: Choosing and setting up a server with Jenkins as Docker image\u00a0\u25baDockerizing Android SDK and Emulator for testing\u00a0 \u25baAutomated Unit- and GUI-Testing for Android in Jenkins\u00a0 \u25baTesting a MongoDB with NodeJS, Mocha and Mongoose During the winter term 2017\/2018, we created an app called Take Me Home. The\u2026","rel":"","context":"In &quot;Mobile Apps&quot;","block_context":{"text":"Mobile Apps","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/interactive-media\/mobile-apps\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2018\/03\/tmh_admin_usermanagement_bearbeitet.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2018\/03\/tmh_admin_usermanagement_bearbeitet.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2018\/03\/tmh_admin_usermanagement_bearbeitet.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2018\/03\/tmh_admin_usermanagement_bearbeitet.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2018\/03\/tmh_admin_usermanagement_bearbeitet.png?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2018\/03\/tmh_admin_usermanagement_bearbeitet.png?resize=1400%2C800&ssl=1 4x"},"classes":[]}],"jetpack_sharing_enabled":true,"authors":[{"term_id":1012,"user_id":1192,"is_guest":0,"slug":"dennis_schmidt","display_name":"Dennis Schmidt","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/95acfc4cd5ffa9cdbee02342ae5270e2a07b5713aa97169864a21cdc1bca5558?s=96&d=mm&r=g","0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""},{"term_id":1007,"user_id":1187,"is_guest":0,"slug":"olivia_restivo","display_name":"Olivia Restivo","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/0b374222addaee11138cfc20d90e49c8effdeca1b5e7aec6e0ae9a220572c9f5?s=96&d=mm&r=g","0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""},{"term_id":1017,"user_id":1193,"is_guest":0,"slug":"niklas_burger","display_name":"Niklas Burger","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/f5d08a203e3b5d1c2fec2561efb9e3a6a2ed80c51289c2327b5567287558e391?s=96&d=mm&r=g","0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""}],"_links":{"self":[{"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/posts\/26146","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/users\/1192"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/comments?post=26146"}],"version-history":[{"count":16,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/posts\/26146\/revisions"}],"predecessor-version":[{"id":26205,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/posts\/26146\/revisions\/26205"}],"wp:attachment":[{"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/media?parent=26146"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/categories?post=26146"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/tags?post=26146"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/ppma_author?post=26146"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}