{"id":26696,"date":"2020-05-20T00:00:00","date_gmt":"2020-05-19T22:00:00","guid":{"rendered":"https:\/\/blexin.com\/angular-microservizi-e-autenticazione-con-identityserver-mongodb-e-docker\/"},"modified":"2021-06-09T12:07:16","modified_gmt":"2021-06-09T10:07:16","slug":"angular-microservices-and-authentication-with-identityserver-mongodb-and-docker","status":"publish","type":"post","link":"https:\/\/blexin.com\/en\/blog-en\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\/","title":{"rendered":"Angular, Microservices and Authentication with IdentityServer, MongoDB and Docker"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"608\" data-attachment-id=\"26670\" data-permalink=\"https:\/\/blexin.com\/en\/blog-en\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\/attachment\/5ea7a0a4-b8a8-442f-9cdf-084c1cec81d0-2\/\" data-orig-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/5ea7a0a4-b8a8-442f-9cdf-084c1cec81d0.png?fit=1024%2C608&amp;ssl=1\" data-orig-size=\"1024,608\" data-comments-opened=\"0\" 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=\"5ea7a0a4-b8a8-442f-9cdf-084c1cec81d0\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/5ea7a0a4-b8a8-442f-9cdf-084c1cec81d0.png?fit=1024%2C608&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/5ea7a0a4-b8a8-442f-9cdf-084c1cec81d0.png?resize=1024%2C608&#038;ssl=1\" alt=\"\" class=\"wp-image-26670\" srcset=\"https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/5ea7a0a4-b8a8-442f-9cdf-084c1cec81d0.png 1024w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/5ea7a0a4-b8a8-442f-9cdf-084c1cec81d0-980x582.png 980w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/5ea7a0a4-b8a8-442f-9cdf-084c1cec81d0-480x285.png 480w\" sizes=\"auto, (min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) and (max-width: 980px) 980px, (min-width: 981px) 1024px, 100vw\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">In a\u00a0<a href=\"https:\/\/blexin.com\/en\/blog-en\/angular-microservices-and-authentication\/\" target=\"_blank\" rel=\"noreferrer noopener\">previous article<\/a>\u00a0of mine, I talked about Microservices and how authenticate an Angular client with them using IdentityServer as authentication authority. I that case, I used the in-memory configuration to simplify the concept, but in a real application we need to save the data in a persistent storage like a database.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Since I used MongoDB in a project for some microservices, I thought it was useful to use the Mongo instance to save also the IdentityServer data, obviously in a separate database; this had interesting implications that are worth telling. Moreover, in a real development scenario, you will never have all the microservices and clients in the same repository, so working on localhost can become a problem, but it is easily solved using dockers and docker-compose. This aspect also has interesting implications because it puts you in front of some networking considerations that are certainly elusive in localhost.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>IdentityServer and MongoDB<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s start with the integration of MongoDB with IdentityServer. There are some libraries ready-to-use for this purpose, but the best ones use Entity Framework as an intermediate layer to store data on MongoDB. I don&#8217;t understand the use of an ORM with a NoSql database, I think it is a nonsense, but I accepted the idea that it&#8217;s a convenience to be able to change storage when I reuse something in a different project, because let&#8217;s face it &#8230; changing databases in a project that is in production is a fairy tale that is told to children and young programmers.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I reused my existing generic implementation of the Repository pattern for MongoDB in the IdentityServer template:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\npublic interface IRepository\n{\n\u00a0\u00a0\u00a0\u00a0IQueryable&lt;T&gt; All&lt;T&gt;() where T : class, new();\n\u00a0\u00a0\u00a0\u00a0IQueryable&lt;T&gt; Where&lt;T&gt;(Expression&lt;Func&lt;T, bool&gt;&gt; expression) where T : class, new();\n\u00a0\u00a0\u00a0\u00a0T Single&lt;T&gt;(Expression&lt;Func&lt;T, bool&gt;&gt; expression) where T : class, new();\n\u00a0\u00a0\u00a0\u00a0void Delete&lt;T&gt;(Expression&lt;Func&lt;T, bool&gt;&gt; expression) where T : class, new();\n\u00a0\u00a0\u00a0\u00a0void Add&lt;T&gt;(T item) where T : class, new();\n\u00a0\u00a0\u00a0\u00a0void Add&lt;T&gt;(IEnumerable&lt;T&gt; items) where T : class, new();\n}\n\u00a0\npublic class MongoRepository : IRepository\n{\n\u00a0\u00a0\u00a0\u00a0private readonly IMongoClient _client;\n\u00a0\u00a0\u00a0\u00a0private readonly IMongoDatabase _database;\n\u00a0\u00a0\n\u00a0\u00a0\u00a0\u00a0public MongoRepository(string mongoConnection, string mongoDatabaseName)\n\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0_client = new MongoClient(mongoConnection);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0_database = _client.GetDatabase(mongoDatabaseName);\n\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\n\u00a0\u00a0\u00a0\u00a0public IQueryable&lt;T&gt; All&lt;T&gt;() where T : class, new()\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0=&gt; _database.GetCollection&lt;T&gt;(typeof(T).Name).AsQueryable();\n\u00a0\u00a0\n\u00a0\u00a0\u00a0\u00a0public IQueryable&lt;T&gt; Where&lt;T&gt;(System.Linq.Expressions.Expression&lt;Func&lt;T, bool&gt;&gt; expression) where T : class, new()\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0=&gt; All&lt;T&gt;().Where(expression);\n\u00a0\u00a0\n\u00a0\u00a0\u00a0\u00a0public void Delete&lt;T&gt;(System.Linq.Expressions.Expression&lt;Func&lt;T, bool&gt; predicate) where T : class, new()\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0=&gt; _database.GetCollection&lt;T&gt;(typeof(T).Name).DeleteMany(predicate);\n\u00a0\u00a0\n\u00a0\u00a0\u00a0\u00a0public T Single&lt;T&gt;(System.Linq.Expressions.Expression&lt;Func&lt;T, bool&gt;&gt; expression) where T : class, new()\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0=&gt; All&lt;T&gt;().Where(expression).SingleOrDefault();\n\u00a0\u00a0\n\u00a0\u00a0\u00a0\u00a0public void Add&lt;T&gt;(T item) where T : class, new()\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0=&gt; _database.GetCollection&lt;T&gt;(typeof(T).Name).InsertOne(item);\n\u00a0\u00a0\n\u00a0\u00a0\u00a0\u00a0public void Add&lt;T&gt;(IEnumerable&lt;T&gt; items) where T : class, new()\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0=&gt; _database.GetCollection&lt;T&gt;(typeof(T).Name).InsertMany(items);\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Nothing complicated, it&#8217;s a simple use of the official C# driver for MongoDB to implement the CRUD operations of the repository. In order to use the repository with IdentityServer, we must implement the&nbsp;<strong>IResourceStore<\/strong>,&nbsp;<strong>IPersistedGrantStore<\/strong>&nbsp;and&nbsp;<strong>IClientStore<\/strong>&nbsp;interfaces with which IdentityServer retrieves the&nbsp;<em>Resources<\/em>,&nbsp;<em>Grants<\/em>&nbsp;and&nbsp;<em>Clients<\/em>&nbsp;to be used in the authentication and token generation process. I take as example the IClientStore implementation, the remaining classes can be found on my GitHub repository:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\npublic class RepositoryClientStore : IClientStore\n{\n\u00a0\u00a0\u00a0\u00a0protected IRepository _repository;\n\u00a0\u00a0\n\u00a0\u00a0\u00a0\u00a0public RepositoryClientStore(IRepository repository)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0=&gt; _repository = repository;\n\u00a0\u00a0\n\u00a0\u00a0\u00a0\u00a0public Task&lt;Client&gt; FindClientByIdAsync(string clientId)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0=&gt; Task.FromResult(_repository.Single&lt;Client&gt;(c =&gt; c.ClientId == clientId));\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s create a class of helpers to register all these interfaces in order to make the configuration of the services more fluent:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\npublic static class RepositoryExtensions\n{\n\u00a0\u00a0\u00a0\u00a0public static IIdentityServerBuilder AddMongoRepository(\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this IIdentityServerBuilder builder,\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0string mongoConnection,\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0string mongoDatabaseName)\n\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0builder.Services.AddTransient&lt;IRepository, MongoRepository&gt;(\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0s =&gt; new MongoRepository(mongoConnection, mongoDatabaseName));\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return builder;\n\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\n\u00a0\u00a0\u00a0\u00a0public static IIdentityServerBuilder AddClients(this IIdentityServerBuilder builder)\n\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0builder.Services.AddTransient&lt;IClientStore, RepositoryClientStore&gt;();\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0builder.Services.AddTransient&lt;ICorsPolicyService, InMemoryCorsPolicyService&gt;();\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return builder;\n\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\n\u00a0\u00a0\u00a0\u00a0public static IIdentityServerBuilder AddIdentityApiResources(this IIdentityServerBuilder builder)\n\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0builder.Services.AddTransient&lt;IResourceStore, RepositoryResourceStore&gt;();\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return builder;\n\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\n\u00a0\u00a0\u00a0\u00a0public static IIdentityServerBuilder AddPersistedGrants(this IIdentityServerBuilder builder)\n\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0builder.Services.AddSingleton&lt;IPersistedGrantStore, RepositoryPersistedGrantStore&gt;();\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return builder;\n\u00a0\u00a0\u00a0\u00a0}\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">At this point the configuration becomes trivial:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\npublic void ConfigureServices(IServiceCollection services)\n{\n\u00a0\u00a0\u00a0\u00a0...\n\u00a0\u00a0\u00a0\u00a0var builder = services.AddIdentityServer(options =&gt;\n\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0options.Events.RaiseErrorEvents = true;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0options.Events.RaiseInformationEvents = true;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0options.Events.RaiseFailureEvents = true;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0options.Events.RaiseSuccessEvents = true;\n\u00a0\u00a0\u00a0\u00a0})\n\u00a0\u00a0\u00a0\u00a0.AddMongoRepository(\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Configuration.GetValue&lt;string&gt;(&quot;MONGO_CONNECTION&quot;),\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Configuration.GetValue&lt;string&gt;(&quot;MONGO_DATABASE_NAME&quot;))\n\u00a0\u00a0\u00a0\u00a0.AddClients()\n\u00a0\u00a0\u00a0\u00a0.AddIdentityApiResources()\n\u00a0\u00a0\u00a0\u00a0.AddPersistedGrants();\n\u00a0\u00a0\n\u00a0\u00a0\u00a0\u00a0seedDatabase(services);\n\u00a0\u00a0\u00a0\u00a0...\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">I also added a private&nbsp;<strong>seedDatabase()<\/strong>&nbsp;method that inserts into the database the data we used in memory if it detects that the respective collections are empty:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nprivate void seedDatabase(IServiceCollection services)\n{\n\u00a0\u00a0\u00a0\u00a0configureMongoDriverIgnoreExtraElements();\n\u00a0\u00a0\u00a0\u00a0var sp = services.BuildServiceProvider();\n\u00a0\u00a0\u00a0\u00a0var repository = sp.GetService&lt;IRepository&gt;();\n\u00a0\u00a0\n\u00a0\u00a0\u00a0\u00a0if (repository.All&lt;Client&gt;().Count() == 0)\n\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0foreach (var client in Config.Clients)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0repository.Add&lt;Client&gt;(client);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0...\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Since we are going to save on Mongo some objects that are not ours, but of IdentityServer, we must instruct MongoDB that it will not find in these classes some extra elements that are added by the database engine during the creation of the documents, such as the&nbsp;<strong>_id<\/strong>&nbsp;property. To do this, I created a private method that I call before any data entry,&nbsp;<strong>configureMongoDriverIgnoreExtraElements()<\/strong>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nprivate void configureMongoDriverIgnoreExtraElements()\n{\n\u00a0\u00a0\u00a0\u00a0var pack = new ConventionPack();\n\u00a0\u00a0\u00a0\u00a0pack.Add(new IgnoreExtraElementsConvention(true));\n\u00a0\u00a0\u00a0\u00a0ConventionRegistry.Register(&quot;IdentityServer Mongo Conventions&quot;, pack, t =&gt; true);\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">In theory, we are done, let&#8217;s go now to test our configuration.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Docker and Docker Compose<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Now we need to run the MongoDB daemon, so we have the opportunity to start configuring our\u00a0<em>docker-compose<\/em>, where at the moment we put only MongoDB. If you do not know Docker you can read\u00a0<a href=\"https:\/\/blexin.com\/it\/blog\/net-core-docker-e-kubernetes\/\">a previous article of mine\u00a0<\/a>or my free book that talks also about Kubernetes (<a href=\"https:\/\/www.syncfusion.com\/ebooks\/using-netcore-docker-and-kubernetes-succinctly\">https:\/\/www.syncfusion.com\/ebooks\/using-netcore-docker-and-kubernetes-succinctly<\/a>).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You can manually create the&nbsp;<strong>docker-compose.yml<\/strong>&nbsp;file in the project root, or use the Docker Tools for Visual Studio Code:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"589\" src=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image01-3.png?resize=1024%2C589&#038;ssl=1\" alt=\"\" class=\"wp-image-26674\" srcset=\"https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image01-3-980x563.png 980w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image01-3-480x276.png 480w\" sizes=\"auto, (min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) and (max-width: 980px) 980px, (min-width: 981px) 1024px, 100vw\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">We modify the script to run the container with MongoDB and expose the port on localhost. In general, it is not a good thing to let Mongo save the data inside the container, but for our examples and only for the development phase, we can avoid creating a volume for them:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nversion: &#039;3.4&#039;\nservices:\n\u00a0mongodb:\n\u00a0\u00a0\u00a0image: mongo:latest\n\u00a0\u00a0\u00a0hostname: mongodb\n\u00a0\u00a0\u00a0ports:\n\u00a0\u00a0\u00a0\u00a0\u00a0- &quot;27017:27017&quot;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">At this point we can run the script (<strong>docker-compose up<\/strong>) and once up, we can launch the&nbsp;<em>IdentityServer<\/em>&nbsp;project with the classic&nbsp;<strong>dotnet run<\/strong>. If it works correctly, you will see the Mongo database collections:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"588\" src=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image02-2.png?resize=1024%2C588&#038;ssl=1\" alt=\"\" class=\"wp-image-26677\" srcset=\"https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image02-2-980x563.png 980w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image02-2-480x276.png 480w\" sizes=\"auto, (min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) and (max-width: 980px) 980px, (min-width: 981px) 1024px, 100vw\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Now let&#8217;s create a Dockerfile to be able to containerize our IdentityServer. In the folder of the&nbsp;<strong>identityserver<\/strong>&nbsp;project, we create a&nbsp;<strong>Dockerfile<\/strong>&nbsp;file which will contain the following instructions:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nFROM mcr.microsoft.com\/dotnet\/core\/sdk:3.1 AS build\nWORKDIR \/app\nCOPY . .\nRUN dotnet restore\nRUN dotnet publish -c Release -o out\n\u00a0\u00a0\nFROM mcr.microsoft.com\/dotnet\/core\/aspnet:3.1 AS runtime\nWORKDIR \/app\nCOPY --from=build \/app\/out .\/\nENTRYPOINT &#x5B;&quot;dotnet&quot;, &quot;identityserver.dll&quot;]\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">We also add a<strong>&nbsp;.Dockerignore<\/strong>&nbsp;to exclude the&nbsp;<strong>bin<\/strong>&nbsp;and&nbsp;<strong>obj<\/strong>&nbsp;folders from the copy of the files in the container:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n\/bin\n\/obj\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s add the build of the Dockerfile to our&nbsp;<strong>docker-compose.yml<\/strong>&nbsp;script in order to have everything ready for the client and the microservices:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nversion: &#039;3.4&#039;\nservices:\n\u00a0identityserver:\n\u00a0\u00a0\u00a0build: .\/identityserver\n\u00a0\u00a0\u00a0environment:\n\u00a0\u00a0\u00a0\u00a0\u00a0- MONGO_CONNECTION=mongodb:\/\/mongodb\n\u00a0\u00a0\u00a0\u00a0\u00a0- MONGO_DATABASE_NAME=identityserber\n\u00a0\u00a0\u00a0ports:\n\u00a0\u00a0\u00a0\u00a0\u00a0- &quot;5000:80&quot;\n\u00a0\u00a0\u00a0depends_on:\n\u00a0\u00a0\u00a0\u00a0\u00a0- mongodb\n\u00a0\u00a0\n\u00a0mongodb:\n\u00a0\u00a0\u00a0image: mongo:latest\n\u00a0\u00a0\u00a0hostname: mongodb\n\u00a0\u00a0\u00a0ports:\n\u00a0\u00a0\u00a0\u00a0\u00a0- &quot;27017:27017&quot;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">We do not need to expose the MongoDB port on localhost, because the&nbsp;<em>identityserver<\/em>&nbsp;container will connect to Mongo using the default network created by Docker and resolve the database address through the service name (<em>mongodb<\/em>). Despite that, I left the port forwarding for convenience, so that I can always connect with a client like&nbsp;<a rel=\"noreferrer noopener\" href=\"https:\/\/robomongo.org\/\" target=\"_blank\">Robo 3T<\/a>, to inspect the collections. Launching the&nbsp;<strong>docker-compose up<\/strong>&nbsp;command, the image for IdentityServer is created (only the first time) and then both containers are launched, then by opening the browser at&nbsp;<strong><a href=\"http:\/\/localhost:5000\/account\/login\" rel=\"nofollow\">http:\/\/localhost:5000\/account\/login<\/a><\/strong>&nbsp;we will see IdentityServer answer correctly:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"660\" src=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image03-2.png?resize=1024%2C660&#038;ssl=1\" alt=\"\" class=\"wp-image-26680\" srcset=\"https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image03-2-1024x660.png 1024w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image03-2-980x631.png 980w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image03-2-480x309.png 480w\" sizes=\"auto, (min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) and (max-width: 980px) 980px, (min-width: 981px) 1024px, 100vw\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">At this point we can launch the Angular client and see if we can authenticate. Let&#8217;s go to the&nbsp;<strong>client-angular<\/strong>&nbsp;folder and run the usual&nbsp;<strong>ng serve<\/strong>&nbsp;command, open the browser at<strong>&nbsp;http:\/\/ localhost:4200<\/strong>&nbsp;and verify that we are redirected to the authentication page:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"593\" src=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image04-2.png?resize=1024%2C593&#038;ssl=1\" alt=\"\" class=\"wp-image-26683\" srcset=\"https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image04-2-980x568.png 980w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image04-2-480x278.png 480w\" sizes=\"auto, (min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) and (max-width: 980px) 980px, (min-width: 981px) 1024px, 100vw\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Unfortunately although the authentication page is reachable, we get a CORS error, which would seem due to the difference between client (4200) and server (5000) port. But why in the previous article did the same example work without problems? Given that often IdentityServer responds with a CORS error also for different errors, such as a data access error, in this case the reported problem is the right one.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In the previous article, the origins of the registered Clients were automatically added to the authorized sources, therefore the&nbsp;<strong>localhost:4200<\/strong>&nbsp;should be among them. However, if we consult the official documentation,&nbsp;<a href=\"https:\/\/identityserver4.readthedocs.io\/en\/latest\/topics\/cors.html\" target=\"_blank\" rel=\"noreferrer noopener\">in the CORS section<\/a>&nbsp;we discover a side effect of not having used Entity Framework:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>\u201cThis default CORS implementation will be in use if you are using either the \u201cin-memory\u201d or EF-based client configuration that we provide. If you define your own IClientStore, then you will need to implement your own custom CORS policy service (see below)\u201d.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So let&#8217;s not get discouraged and implement our CORS policy service:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\npublic class RepositoryCorsPolicyService : ICorsPolicyService\n{\n\u00a0\u00a0\u00a0\u00a0private readonly string&#x5B;] _allowedOrigins;\n\u00a0\u00a0\n\u00a0\u00a0\u00a0\u00a0public RepositoryCorsPolicyService(IRepository repository)\n\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0_allowedOrigins = repository.All&lt;Client&gt;().SelectMany(x =&gt; x.AllowedCorsOrigins).ToArray();\n\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\n\u00a0\u00a0\u00a0\u00a0public Task&lt;bool&gt; IsOriginAllowedAsync(string origin)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0=&gt; Task.FromResult(_allowedOrigins.Contains(origin));\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">We just have to register our implementation:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\npublic void ConfigureServices(IServiceCollection services)\n{\n\u00a0\u00a0\u00a0\u00a0...\n\u00a0\u00a0\u00a0\u00a0var builder = services.AddIdentityServer(options =&gt;\n\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0...\n\u00a0\u00a0\u00a0\u00a0})\n\u00a0\u00a0\n\u00a0\u00a0\u00a0\u00a0...\n\u00a0\u00a0\u00a0\u00a0services.AddSingleton&lt;ICorsPolicyService, RepositoryCorsPolicyService&gt;();\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Remember to add your registration AFTER&nbsp;<strong>AddIdentityServer()<\/strong>, otherwise it will be overwritten by the standard one that will not interrogate your Clients. We force the regeneration of the Docker image using the&nbsp;<strong>docker-compose build &#8211;no-cache<\/strong>&nbsp;command and try again with&nbsp;<strong>docker-compose up<\/strong>:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"548\" src=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image05-2.png?resize=1024%2C548&#038;ssl=1\" alt=\"\" class=\"wp-image-26686\" srcset=\"https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image05-2-980x525.png 980w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image05-2-480x257.png 480w\" sizes=\"auto, (min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) and (max-width: 980px) 980px, (min-width: 981px) 1024px, 100vw\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">This time everything will work correctly, giving us access to the application immediately after authentication. If you try to launch microservices too, you will see that they will respond without problems. So we finished? To complete the tour we just have to dockerize the two microservices, making the communication parameters with IdentityServer configurable, since we are no longer in localhost, but in the default Docker network:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\npublic void ConfigureServices(IServiceCollection services)\n{\n\u00a0\u00a0\u00a0\u00a0services.AddAuthentication(options =&gt;\n\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0...\n\u00a0\u00a0\u00a0\u00a0}).AddJwtBearer(o =&gt;\n\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0o.Authority = Configuration.GetValue&lt;string&gt;(&quot;IDENTITY_AUTHORITY&quot;);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0o.Audience = Configuration.GetValue&lt;string&gt;(&quot;IDENTITY_AUDIENCE&quot;);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0o.RequireHttpsMetadata = Configuration.GetValue&lt;bool&gt;(&quot;IDENTITY_REQUIREHTTPSMETADATA&quot;);\n\u00a0\u00a0\u00a0\u00a0});\n\u00a0\u00a0\u00a0\u00a0...\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">At this point we can use the same Dockerfile used for IdentityServer (they are both ASP.NET Core applications) in which we only change the name of the assembly to be launched on&nbsp;<strong>ENTRYPOINT<\/strong>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n...\nENTRYPOINT &#x5B;&quot;dotnet&quot;, &quot;microservice1.dll&quot;]\n\u00a0\u00a0\n...\nENTRYPOINT &#x5B;&quot;dotnet&quot;, &quot;microservice2.dll&quot;]\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">We modify the&nbsp;<strong>docker-compose.yml<\/strong>&nbsp;file by adding the two services:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nversion: &#039;3.4&#039;\nservices:\n\u00a0microservice1:\n\u00a0\u00a0\u00a0build: .\/microservice1\n\u00a0\u00a0\u00a0environment:\n\u00a0\u00a0\u00a0\u00a0\u00a0- IDENTITY_AUTHORITY=http:\/\/identityserver\n\u00a0\u00a0\u00a0ports:\n\u00a0\u00a0\u00a0\u00a0\u00a0- &quot;5002:80&quot;\n\u00a0\u00a0\u00a0depends_on:\n\u00a0\u00a0\u00a0\u00a0\u00a0- identityserver\n\u00a0\u00a0\n\u00a0microservice2:\n\u00a0\u00a0\u00a0build: .\/microservice2\n\u00a0\u00a0\u00a0environment:\n\u00a0\u00a0\u00a0\u00a0\u00a0- IDENTITY_AUTHORITY=http:\/\/identityserver\n\u00a0\u00a0\u00a0ports:\n\u00a0\u00a0\u00a0\u00a0\u00a0- &quot;5003:80&quot;\n\u00a0\u00a0\u00a0depends_on:\n\u00a0\u00a0\u00a0\u00a0\u00a0- identityserver\n\u00a0\u00a0\n\u00a0identityserver:\n\u00a0\u00a0\u00a0build: .\/identityserver\n\u00a0\u00a0\u00a0...\n\u00a0\u00a0\n\u00a0mongodb:\n\u00a0\u00a0\u00a0image: mongo:latest\n\u00a0\u00a0\u00a0...\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Note that the authority address is no longer&nbsp;<strong><a href=\"http:\/\/localhost:5000\" rel=\"nofollow\">http:\/\/localhost:5000<\/a><\/strong>&nbsp;but we set it to&nbsp;<strong><a href=\"http:\/\/identityserver\" rel=\"nofollow\">http:\/\/identityserver<\/a><\/strong>, using the name of the service to resolve the IP of the identityserver container in the default network created by Docker for us. We launch the&nbsp;<strong>docker-compose up<\/strong>&nbsp;command, which will take a little longer to create the images of the microservices, and test the invocations:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"754\" src=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image06-2.png?resize=1024%2C754&#038;ssl=1\" alt=\"\" class=\"wp-image-26689\" srcset=\"https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image06-2-980x722.png 980w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image06-2-480x354.png 480w\" sizes=\"auto, (min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) and (max-width: 980px) 980px, (min-width: 981px) 1024px, 100vw\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">As you can see, we get a 401 error because our token is invalid due to the&nbsp;<em>issuer<\/em>&nbsp;value. The official documentation of the&nbsp;<a href=\"https:\/\/tools.ietf.org\/html\/rfc7523\" target=\"_blank\" rel=\"noreferrer noopener\">JWT standard<\/a>&nbsp;tells us:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>\u201cThe JWT MUST contain an &#8220;iss&#8221; (issuer) claim that contains a unique identifier for the entity that issued the JWT. In the absence of an application profile specifying otherwise,compliant applications MUST compare issuer values using the Simple String Comparison method defined in Section 6.2.1 of RFC39862\u201d<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Everything worked fine in localhost because IdentityServer generates this value for us, as it is clearly explicit by the&nbsp;<a href=\"http:\/\/docs.identityserver.io\/en\/3.1.0\/reference\/options.html\" target=\"_blank\" rel=\"noreferrer noopener\">official documentation<\/a>:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>\u201cIssuerUri: Set the issuer name that will appear in the discovery document and the issued JWT tokens. It is recommended to not set this property, which infers the issuer name from the host name that is used by the clients.\u201d<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Therefore, when generating the token requested by our client, it used&nbsp;<strong><a href=\"http:\/\/localhost:5000&#038;nbsp\" rel=\"nofollow\">http:\/\/localhost:5000&#038;nbsp<\/a>;<\/strong>as issuer, while our microservice contacts IdentityServer to validate the token using the&nbsp;<strong><a href=\"http:\/\/identityserver\" rel=\"nofollow\">http:\/\/identityserver<\/a><\/strong>&nbsp;authority that we have configured in the docker-compose script. In production we would have no problem since these would coincide, but in this hybrid case instead we have to force the hand of IdentityServer, using a fixed&nbsp;<strong>IssuerUri<\/strong>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nvar builder = services.AddIdentityServer(options =&gt;\n{\noptions.IssuerUri = Configuration.GetValue&lt;string&gt;(&quot;ISSUER_URI&quot;);\n...\n})\n.AddMongoRepository(\nConfiguration.GetValue&lt;string&gt;(&quot;MONGO_CONNECTION&quot;),\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Configuration.GetValue&lt;string&gt;(&quot;MONGO_DATABASE_NAME&quot;))\n.AddClients()\n.AddIdentityApiResources()\n.AddPersistedGrants();\n<\/pre><\/div>\n\n\n<h2 class=\"wp-block-heading\"><strong>Conclusions<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">With this change everything works properly again! You can check it by yourself downloading and running the sources you can find here:&nbsp;<a href=\"https:\/\/github.com\/apomic80\/angular-microservices-identityserver\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/github.com\/apomic80\/angular-microservices-identityserver<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you want to learn more about Docker and Docker Compose, you can watch the recordings of our Antonio&#8217;s live broadcasts; he dealt with issues related to DevOps on his Twitch channel:\u00a0<a href=\"https:\/\/www.twitch.tv\/turibbio\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/www.twitch.tv\/turibbio<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Happy Coding!<\/em><\/p>\n\n\n\n\n","protected":false},"excerpt":{"rendered":"<p>Let\u2019s see how to manage authentication in a microservices architecture using ASP.NET Core, Angular, IdentityServer, MongoDB and Docker<\/p>\n","protected":false},"author":196716248,"featured_media":26670,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"off","_et_pb_old_content":"","_et_gb_content_width":"","_coblocks_attr":"","_coblocks_dimensions":"","_coblocks_responsive_height":"","_coblocks_accordion_ie_support":"","inline_featured_image":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"{title}\n\n{excerpt}\n\n{url}","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"_wpas_customize_per_network":false,"jetpack_post_was_ever_published":false},"categories":[688637524],"tags":[688637390,688637416,688637384,688637546,688637427,688637428,688637429],"class_list":["post-26696","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-en","tag-angular-en","tag-asp-net-core-en","tag-c-en","tag-docker-en","tag-identityserver-en","tag-microservices-en","tag-mongdb-en"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.8 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Angular, Microservices and Authentication with IdentityServer, MongoDB and Docker - Blexin<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/blexin.com\/en\/blog-en\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Angular, Microservices and Authentication with IdentityServer, MongoDB and Docker - Blexin\" \/>\n<meta property=\"og:description\" content=\"Let\u2019s see how to manage authentication in a microservices architecture using ASP.NET Core, Angular, IdentityServer, MongoDB and Docker\" \/>\n<meta property=\"og:url\" content=\"https:\/\/blexin.com\/en\/blog-en\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\/\" \/>\n<meta property=\"og:site_name\" content=\"Blexin\" \/>\n<meta property=\"article:published_time\" content=\"2020-05-19T22:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2021-06-09T10:07:16+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/i1.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/5ea7a0a4-b8a8-442f-9cdf-084c1cec81d0.png?fit=1024%2C608&ssl=1\" \/>\n\t<meta property=\"og:image:width\" content=\"1024\" \/>\n\t<meta property=\"og:image:height\" content=\"608\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Michele Aponte\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Michele Aponte\" \/>\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:\\\/\\\/blexin.com\\\/en\\\/blog-en\\\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/blog-en\\\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\\\/\"},\"author\":{\"name\":\"Michele Aponte\",\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/#\\\/schema\\\/person\\\/cdc5540c3b6edcacd8d760669e797005\"},\"headline\":\"Angular, Microservices and Authentication with IdentityServer, MongoDB and Docker\",\"datePublished\":\"2020-05-19T22:00:00+00:00\",\"dateModified\":\"2021-06-09T10:07:16+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/blog-en\\\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\\\/\"},\"wordCount\":1607,\"image\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/blog-en\\\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/i0.wp.com\\\/blexin.com\\\/wp-content\\\/uploads\\\/2020\\\/12\\\/5ea7a0a4-b8a8-442f-9cdf-084c1cec81d0.png?fit=1024%2C608&ssl=1\",\"keywords\":[\"Angular\",\"Asp.net core\",\"C#\",\"Docker\",\"Identityserver\",\"Microservices\",\"MongDB\"],\"articleSection\":[\"Blog\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/blog-en\\\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\\\/\",\"url\":\"https:\\\/\\\/blexin.com\\\/en\\\/blog-en\\\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\\\/\",\"name\":\"Angular, Microservices and Authentication with IdentityServer, MongoDB and Docker - Blexin\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/blog-en\\\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/blog-en\\\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/i0.wp.com\\\/blexin.com\\\/wp-content\\\/uploads\\\/2020\\\/12\\\/5ea7a0a4-b8a8-442f-9cdf-084c1cec81d0.png?fit=1024%2C608&ssl=1\",\"datePublished\":\"2020-05-19T22:00:00+00:00\",\"dateModified\":\"2021-06-09T10:07:16+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/#\\\/schema\\\/person\\\/cdc5540c3b6edcacd8d760669e797005\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/blog-en\\\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/blexin.com\\\/en\\\/blog-en\\\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/blog-en\\\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\\\/#primaryimage\",\"url\":\"https:\\\/\\\/i0.wp.com\\\/blexin.com\\\/wp-content\\\/uploads\\\/2020\\\/12\\\/5ea7a0a4-b8a8-442f-9cdf-084c1cec81d0.png?fit=1024%2C608&ssl=1\",\"contentUrl\":\"https:\\\/\\\/i0.wp.com\\\/blexin.com\\\/wp-content\\\/uploads\\\/2020\\\/12\\\/5ea7a0a4-b8a8-442f-9cdf-084c1cec81d0.png?fit=1024%2C608&ssl=1\",\"width\":1024,\"height\":608},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/blog-en\\\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/blexin.com\\\/en\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Angular, Microservices and Authentication with IdentityServer, MongoDB and Docker\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/#website\",\"url\":\"https:\\\/\\\/blexin.com\\\/en\\\/\",\"name\":\"Blexin\",\"description\":\"Con noi \u00e8 semplice\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/blexin.com\\\/en\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/#\\\/schema\\\/person\\\/cdc5540c3b6edcacd8d760669e797005\",\"name\":\"Michele Aponte\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/32138aff568f2063b34d27a23cef27e09f3159bfcadea5ea05599c499cf4342f?s=96&d=identicon&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/32138aff568f2063b34d27a23cef27e09f3159bfcadea5ea05599c499cf4342f?s=96&d=identicon&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/32138aff568f2063b34d27a23cef27e09f3159bfcadea5ea05599c499cf4342f?s=96&d=identicon&r=g\",\"caption\":\"Michele Aponte\"},\"url\":\"https:\\\/\\\/blexin.com\\\/en\\\/author\\\/michele-aponteblexin-com\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Angular, Microservices and Authentication with IdentityServer, MongoDB and Docker - Blexin","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:\/\/blexin.com\/en\/blog-en\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\/","og_locale":"en_US","og_type":"article","og_title":"Angular, Microservices and Authentication with IdentityServer, MongoDB and Docker - Blexin","og_description":"Let\u2019s see how to manage authentication in a microservices architecture using ASP.NET Core, Angular, IdentityServer, MongoDB and Docker","og_url":"https:\/\/blexin.com\/en\/blog-en\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\/","og_site_name":"Blexin","article_published_time":"2020-05-19T22:00:00+00:00","article_modified_time":"2021-06-09T10:07:16+00:00","og_image":[{"width":1024,"height":608,"url":"https:\/\/i1.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/5ea7a0a4-b8a8-442f-9cdf-084c1cec81d0.png?fit=1024%2C608&ssl=1","type":"image\/png"}],"author":"Michele Aponte","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Michele Aponte","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/blexin.com\/en\/blog-en\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\/#article","isPartOf":{"@id":"https:\/\/blexin.com\/en\/blog-en\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\/"},"author":{"name":"Michele Aponte","@id":"https:\/\/blexin.com\/en\/#\/schema\/person\/cdc5540c3b6edcacd8d760669e797005"},"headline":"Angular, Microservices and Authentication with IdentityServer, MongoDB and Docker","datePublished":"2020-05-19T22:00:00+00:00","dateModified":"2021-06-09T10:07:16+00:00","mainEntityOfPage":{"@id":"https:\/\/blexin.com\/en\/blog-en\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\/"},"wordCount":1607,"image":{"@id":"https:\/\/blexin.com\/en\/blog-en\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\/#primaryimage"},"thumbnailUrl":"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/5ea7a0a4-b8a8-442f-9cdf-084c1cec81d0.png?fit=1024%2C608&ssl=1","keywords":["Angular","Asp.net core","C#","Docker","Identityserver","Microservices","MongDB"],"articleSection":["Blog"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/blexin.com\/en\/blog-en\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\/","url":"https:\/\/blexin.com\/en\/blog-en\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\/","name":"Angular, Microservices and Authentication with IdentityServer, MongoDB and Docker - Blexin","isPartOf":{"@id":"https:\/\/blexin.com\/en\/#website"},"primaryImageOfPage":{"@id":"https:\/\/blexin.com\/en\/blog-en\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\/#primaryimage"},"image":{"@id":"https:\/\/blexin.com\/en\/blog-en\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\/#primaryimage"},"thumbnailUrl":"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/5ea7a0a4-b8a8-442f-9cdf-084c1cec81d0.png?fit=1024%2C608&ssl=1","datePublished":"2020-05-19T22:00:00+00:00","dateModified":"2021-06-09T10:07:16+00:00","author":{"@id":"https:\/\/blexin.com\/en\/#\/schema\/person\/cdc5540c3b6edcacd8d760669e797005"},"breadcrumb":{"@id":"https:\/\/blexin.com\/en\/blog-en\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blexin.com\/en\/blog-en\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/blexin.com\/en\/blog-en\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\/#primaryimage","url":"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/5ea7a0a4-b8a8-442f-9cdf-084c1cec81d0.png?fit=1024%2C608&ssl=1","contentUrl":"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/5ea7a0a4-b8a8-442f-9cdf-084c1cec81d0.png?fit=1024%2C608&ssl=1","width":1024,"height":608},{"@type":"BreadcrumbList","@id":"https:\/\/blexin.com\/en\/blog-en\/angular-microservices-and-authentication-with-identityserver-mongodb-and-docker\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/blexin.com\/en\/"},{"@type":"ListItem","position":2,"name":"Angular, Microservices and Authentication with IdentityServer, MongoDB and Docker"}]},{"@type":"WebSite","@id":"https:\/\/blexin.com\/en\/#website","url":"https:\/\/blexin.com\/en\/","name":"Blexin","description":"Con noi \u00e8 semplice","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blexin.com\/en\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/blexin.com\/en\/#\/schema\/person\/cdc5540c3b6edcacd8d760669e797005","name":"Michele Aponte","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/32138aff568f2063b34d27a23cef27e09f3159bfcadea5ea05599c499cf4342f?s=96&d=identicon&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/32138aff568f2063b34d27a23cef27e09f3159bfcadea5ea05599c499cf4342f?s=96&d=identicon&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/32138aff568f2063b34d27a23cef27e09f3159bfcadea5ea05599c499cf4342f?s=96&d=identicon&r=g","caption":"Michele Aponte"},"url":"https:\/\/blexin.com\/en\/author\/michele-aponteblexin-com\/"}]}},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/5ea7a0a4-b8a8-442f-9cdf-084c1cec81d0.png?fit=1024%2C608&ssl=1","jetpack_shortlink":"https:\/\/wp.me\/pcyUBx-6WA","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/blexin.com\/en\/wp-json\/wp\/v2\/posts\/26696","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blexin.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blexin.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blexin.com\/en\/wp-json\/wp\/v2\/users\/196716248"}],"replies":[{"embeddable":true,"href":"https:\/\/blexin.com\/en\/wp-json\/wp\/v2\/comments?post=26696"}],"version-history":[{"count":9,"href":"https:\/\/blexin.com\/en\/wp-json\/wp\/v2\/posts\/26696\/revisions"}],"predecessor-version":[{"id":33048,"href":"https:\/\/blexin.com\/en\/wp-json\/wp\/v2\/posts\/26696\/revisions\/33048"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blexin.com\/en\/wp-json\/wp\/v2\/media\/26670"}],"wp:attachment":[{"href":"https:\/\/blexin.com\/en\/wp-json\/wp\/v2\/media?parent=26696"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blexin.com\/en\/wp-json\/wp\/v2\/categories?post=26696"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blexin.com\/en\/wp-json\/wp\/v2\/tags?post=26696"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}