I have an API and I am using IdentityServer4 for authentication. So, I have a solution with my API and my Identity Server projects in it. So far so good. I've tested the API without authentication and it works fine. Now I'm trying to test it with Authentication, using Postman, and I am running into an issue. I am trying to request a token, using the Authorization Code grant type, and I put in all the info needed. The error I keep getting in the console is
09:51:31 Information] IdentityServer4.ResponseHandling.AuthorizeInteractionResponseGenerator Showing login: User is not authenticated
I've looked online for tutorials that show how to set up an API and Identity Server4, but all of them want to create a client and show a login screen. I don't need a login for this API, and I have no idea what my client is going to do. All I want is for the client to be able to authorize using a clientID and a client Secret. And then get an access token that they can use for the rest of the API calls. How can I do this? Below is my startup for my API and for the IDP
API Startup
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddHttpContextAccessor();
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = "https://localhost:5001";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false
};
});
// adds an authorization policy to make sure the token is for scope 'api1'
services.AddAuthorization(options =>
{
options.AddPolicy("ApiScope", policy =>
{
policy.RequireAuthenticatedUser();
policy.RequireClaim("scope", "URCSAPI");
});
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
IDP Startup
public class Startup
{
public IWebHostEnvironment Environment { get; }
public Startup(IWebHostEnvironment environment)
{
Environment = environment;
}
public void ConfigureServices(IServiceCollection services)
{
var URCSIDPDataDBConnectionString =
"Server=localhost;Database=URCSIDP;Trusted_Connection=True;MultipleActiveResultSets=true";
// uncomment, if you want to add an MVC-based UI
services.AddControllersWithViews();
var builder = services.AddIdentityServer();
//.AddInMemoryIdentityResources(Config.Ids)
//.AddInMemoryApiResources(Config.Apis)
//.AddInMemoryClients(Config.Clients)
//.AddTestUsers(TestUsers.Users);
// not recommended for production - you need to store your key material somewhere secure
builder.AddDeveloperSigningCredential();
//builder.AddSigningCredential(LoadCertificateFromStore());
var migrationsAssembly = typeof(Startup)
.GetTypeInfo().Assembly.GetName().Name;
builder.AddConfigurationStore(options =>
{
options.ConfigureDbContext = builder =>
builder.UseSqlServer(URCSIDPDataDBConnectionString,
options => options.MigrationsAssembly(migrationsAssembly));
});
builder.AddOperationalStore(options =>
{
options.ConfigureDbContext = builder =>
builder.UseSqlServer(URCSIDPDataDBConnectionString,
options => options.MigrationsAssembly(migrationsAssembly));
});
}
public void Configure(IApplicationBuilder app)
{
if (Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
//InitializeDatabase(app);
// uncomment if you want to add MVC
//app.UseStaticFiles();
//app.UseRouting();
app.UseIdentityServer();
// uncomment, if you want to add MVC
//app.UseAuthorization();
//app.UseEndpoints(endpoints =>
//{
// endpoints.MapDefaultControllerRoute();
//});
}
public X509Certificate2 LoadCertificateFromStore()
{
string thumbPrint = "d4d681b3de4cd26fc030292aeea170e553810bdb";
using (var store = new X509Store(StoreName.My, StoreLocation.LocalMachine))
{
store.Open(OpenFlags.ReadOnly);
var certCollection = store.Certificates.Find(X509FindType.FindByThumbprint,
thumbPrint, true);
if (certCollection.Count == 0)
{
throw new Exception("The specified certificate wasn't found.");
}
return certCollection[0];
}
}
}
Update: Adding the config file I used to add the info to the DB:
public static class Config
{
public static IEnumerable<IdentityResource> Ids =>
new IdentityResource[]
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
new IdentityResources.Address()
};
public static IEnumerable<ApiResource> Apis =>
new ApiResource[]
{
new ApiResource(
"URCSAPI",
"Unit Rate ContractSystem API")
{
ApiSecrets = { new Secret("apisecret".Sha256()) }
}
};
public static IEnumerable<Client> Clients =>
new Client[]
{
new Client
{
AccessTokenType = AccessTokenType.Reference,
AccessTokenLifetime = 120,
AllowOfflineAccess = true,
UpdateAccessTokenClaimsOnRefresh = true,
ClientName = "Tesla",
ClientId = "Tesla",
AllowedGrantTypes = GrantTypes.ClientCredentials,
RequirePkce = false,
RedirectUris = new List<string>()
{
"https://localhost:6001/signin-oidc"
},
PostLogoutRedirectUris = new List<string>()
{
"https://localhost:6001/signout-callback-oidc"
},
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Address,
"URCSAPI"
},
ClientSecrets =
{
new Secret("secret".Sha256())
}
}
};
}