Identity Server 4: Why i receive unauthorized_client? - model-view-controller

This is my initial setting for my mvc connecting with identity server.
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
AuthenticationType = "oidc",
SignInAsAuthenticationType = "Cookies",
Authority = "http://identity.azurewebsites.net",
RedirectUri = "http://localhost:62419/signin-oidc",
PostLogoutRedirectUri = "http://localhost:62419/signout-callback-oidc",
ClientId = "mvc",
ResponseType = "id_token",
Scope = "openid profile",
UseTokenLifetime = false,
RequireHttpsMetadata = false,
Notifications = new OpenIdConnectAuthenticationNotifications
{
SecurityTokenValidated = (context) =>
{
var identity = context.AuthenticationTicket.Identity;
var name = identity.Claims.FirstOrDefault(c => c.Type == identity.NameClaimType)?.Value;
return Task.FromResult(0);
}
}
});
I can get to the identity server. I received a message
Sorry, there was an error : unauthorized_client
Invalid redirect_uri
I have added the redirectUri into the ClientRedirectUris table matched with the code shown above. Is there any other area i forgot to add or set.
Request url: http://identity.azurewebsites.net/home/error?errorId=CfDJ8BPcf2qEDmRMt0TtYfAIujdUrTeIfqktT2TIcVFNomo6u6QFAROi-gEI2wXHP8kbmmiSYIK1aRV1nL-h6tFY_KeZabkMhIzy-V_0vvo2-hUFfj6I66qJWSjPiRhSYmGZa_-kYlULMb8a1Bz6UQ9UV5L6VdLscQRhScCpnOYpM6Ku84KM_S-4eZXrAX13EaVhqjxhpNhD8jIU9kJkjAn1t6sLVGrfZSEM0tAOGkTXFvBzuoucYURIFhZPJPGjVuJuRegrS2vsLPALHJCv3MLrW9ImudDeCkgf9VhAHwrRLfP3TB_7i4OvEffZwhuDuCSoyQ

You have to make sure the redirect url matches a redirect url in your client configuration in IdentityServer. For example
new Client
{
ClientId = "mvc",
ClientName = "MVC Client",
AllowedGrantTypes = GrantTypes.Implicit,
// where to redirect to after login
RedirectUris = { "http://localhost:62419/signin-oidc" },
// where to redirect to after logout
PostLogoutRedirectUris = { "http://localhost:62419/signout-callback-oidc" },
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile
}
}
Make sure RedirectUris matches the redirect url set in your client 'http://localhost:62419/signin-oidc'

Also, make sure your scope matches the AlowedScopes in your client configuration. It would help if we could see the request URL. i.e.
https://identity.azurewebsites.net/connect/authorize?
client_id=mvc
&redirect_uri=http://localhost:62419/signin-oidc
&response_type=id_token
&scope=openid profile
&nonce=63653346343504
&state=CfDJAJDR
&response_mode=form_post

Related

Zoho Invoice API Error {"error":"invalid_client"} while requesting for token

While accessing Zoho api to get the token I'm getting the following error:
{"error":"invalid_client"}
Step 1: I'm requesting for Auth Code and the auth code is returned successfully.
This is the API I'm using.
https://accounts.zoho.com/oauth/v2/auth?scope=xxx&client_id=yyyyy&state=zzzz&response_type=code&redirect_uri=pppppp&access_type=offline
Step 2: Token Request
With the Auth Code obtained in Step-1 I'm doing a post request for the token at that time only I'm getting the below exception.
var authTokenRequestData = new
{
code= code,
client_id= _clientId,
client_secret =_clientSecret,
redirect_uri = _redirectUri,
grant_type = "authorization_code"
};
var data = new StringContent(JsonConvert.SerializeObject(authTokenRequestData), Encoding.UTF8, "application/json");
var url = "https://accounts.zoho.com/oauth/v2/token";
string result = "";
using (var client = new HttpClient())
{
var response = await client.PostAsync(url, data);
result = await response.Content.ReadAsStringAsync();
}
It's giving me the exception
{error:invalid_client}
I've verified my client_id and client_secret. It's correct only.
It's Server-Based-Application client I've registered.
Any help is highly appreciated on this.
There could be one more reason for this issue.
{"error":"invalid_client"}
Check if you're using the correct domain. (.in .com or...)
For example, you're using .in instead of .com or vice-versa
In my case when I was using .in domain but my domain was .com I was getting the same error {"error":"invalid_client"}
I was using this:
var url = "https://accounts.zoho.in/oauth/v2/token";
I replaced it as below and that solved my issue.
var url = "https://accounts.zoho.com/oauth/v2/token";
I could solve this issue by changing the request Content-Type
"Content-Type", "application/x-www-form-urlencoded"
Complete code is as follows:
string _domain = ".in"; /*Ensure you're using the correct .com or .in domain*/
var url = "https://accounts.zoho"+ _domain + "/oauth/v2/token";
string result = "";
using (var client = new HttpClient())
{
var data = new Dictionary<string, string>
{
{ "Content-Type", "application/x-www-form-urlencoded" },
{ "code", code },
{ "client_id", _clientId },
{ "client_secret", _clientSecret },
{ "redirect_uri", _redirectUri },
{ "grant_type", "authorization_code" },
{ "access_type", "offline" }
};
var response = await client.PostAsync(url, new FormUrlEncodedContent(data));
result = await response.Content.ReadAsStringAsync();
}

AddJwtBearer validates token but kills request

Following is my code to register authentication
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = signingKey,
ValidateIssuer = true,
ValidIssuer = issuer,
ValidateAudience = true,
ValidAudience = audience,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
services.AddAuthentication(options =>
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = tokenValidationParameters;
options.Events = new JwtBearerEvents
{
OnAuthenticationFailed = context =>
{
Console.WriteLine("OnAuthenticationFailed: " + context.Exception.Message);
Trace.WriteLine("OnAuthenticationFailed: " + context.Exception.Message);
return Task.CompletedTask;
},
OnTokenValidated = context =>
{
Console.WriteLine("OnTokenValidated: " + context.SecurityToken);
Trace.WriteLine("OnTokenValidated: " + context.SecurityToken);
return Task.CompletedTask;
}
};
});
Following is my controller code
[Route("api/[controller]")]
public class ValuesController : Controller
{
// GET api/values
[HttpGet]
[Authorize]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
}
But my request to api/values never makes it to this controller.
Somehow the request completes in OnTokenValidated event.
I get 401 response.
What am I doing wrong here?
To my understanding, when using Identity the defaultAuthenticateScheme is set to cookie authentication.
I am unsure what options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; is supposed to do but it didn't change the DefaultAuthenticateScheme or DefaultChallengeScheme when I tested it in my program that is using JWT authentication with identity.
try adding in
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
and then to prevent getting a 404 instead of a 401 when not authorized add
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
if you want to use cookie authentication with JWT you can set the DefaultAuthenticatieScheme in the [Authorize] tag like so either:
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

Simple Authentication using Jwt in dot net core MVC

I'm trying to add JWT validation in my dot net core application. I've followed this link to understand JWT and able to generate a token by givings some values like this.
var token = new JwtSecurityToken(
issuer: issuer,
audience: aud,
claims: claims,
expires: expTime,
signingCredentials: creds
);
Edit: and to follow this answer, I've also added JwtBearerAuthentication middleware in my app by adding app.UseJwtBearerAuthentication(new JwtBearerOptions { /* options */ }) to Startup.Configure() method.
Now I'm stuck how could I pass this token inside HTTP header? I'm generating this token on Login but whats next? How could I get to know that JWT is added and working fine??
Any kind of help will be appreciated.
This is a runnable sample for bearer token authentication in ASP.NET Core.
How to achieve a bearer token authentication and authorization in ASP.NET Core
At back end, you can generate the token following this code:
[Route("api/[controller]")]
public class TokenAuthController : Controller
{
[HttpPost]
public string GetAuthToken(User user)
{
var existUser = UserStorage.Users.FirstOrDefault(u => u.Username == user.Username && u.Password == user.Password);
if (existUser != null)
{
var requestAt = DateTime.Now;
var expiresIn = requestAt + TokenAuthOption.ExpiresSpan;
var token = GenerateToken(existUser, expiresIn);
return JsonConvert.SerializeObject(new {
stateCode = 1,
requertAt = requestAt,
expiresIn = TokenAuthOption.ExpiresSpan.TotalSeconds,
accessToken = token
});
}
else
{
return JsonConvert.SerializeObject(new { stateCode = -1, errors = "Username or password is invalid" });
}
}
private string GenerateToken(User user, DateTime expires)
{
var handler = new JwtSecurityTokenHandler();
ClaimsIdentity identity = new ClaimsIdentity(
new GenericIdentity(user.Username, "TokenAuth"),
new[] {
new Claim("ID", user.ID.ToString())
}
);
var securityToken = handler.CreateToken(new SecurityTokenDescriptor
{
Issuer = TokenAuthOption.Issuer,
Audience = TokenAuthOption.Audience,
SigningCredentials = TokenAuthOption.SigningCredentials,
Subject = identity,
Expires = expires
});
return handler.WriteToken(securityToken);
}
}
In Startup.cs/ConfigureServices method
services.AddAuthorization(auth =>
{
auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme‌​)
.RequireAuthenticatedUser().Build());
});
And add this code in Configure method
app.UseJwtBearerAuthentication(new JwtBearerOptions {
TokenValidationParameters = new TokenValidationParameters {
IssuerSigningKey = TokenAuthOption.Key,
ValidAudience = TokenAuthOption.Audience,
ValidIssuer = TokenAuthOption.Issuer,
ValidateIssuerSigningKey = true,
ValidateLifetime = true,
ClockSkew = TimeSpan.FromMinutes(0)
}
});
At front end, you just add the token to header like this:
$.ajaxSetup({
headers: { "Authorization": "Bearer " + accessToken }
});
or
$.ajax("http://somedomain/somepath/somepage",{
headers:{ "Authorization": "Bearer " + accessToken },
/*some else parameter for ajax, see more you can review the Jquery API*/
});

SignalR 403 status code on websocket transport handshake

I am mapping signalR in Web Api by following code in Startup.cs class
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration
{
EnableDetailedErrors= true,
EnableJSONP=true
};
map.RunSignalR(hubConfiguration);
});
}
Along with it i used Bearer token authentication and cookies authentication in Web Api by following code
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
AuthenticationMode = AuthenticationMode.Active,
CookieHttpOnly = true,
CookieSecure = CookieSecureOption.SameAsRequest,
CookiePath = "/",
CookieDomain = "xxxx.cloudapp.net",
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true,
};
app.UseOAuthBearerTokens(OAuthOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()
{
Provider = new QueryStringOAuthBearerProvider("Token")
});
Web Api is on different domain so i enabled Cors for Api calls by following code
public static void Register(HttpConfiguration config)
{
var cors = new EnableCorsAttribute("http://localhost:8080,http://www.myweb.com,http://myweb.com", "*", "*");
cors.SupportsCredentials = true;
config.EnableCors(cors);
......
......
}
Now, while connecting from client side, I am getting following error in console
Here is response that i am getting in corresponding to websocket handshake
Please guide on this.
I know this is an old question, but I've had the same problem, so for future reference if anyone else stumbles upon it...
Somehow this:
CookieSecure = CookieSecureOption.SameAsRequest,
is the problem.
It doesnt work as it should (don't know why)...
This is my cookie configuration:
builder.Register(ctx => new CookieAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AuthenticationType = CookieAuthenticationDefaults.AuthenticationType,
CookieName = "xxx",
CookieHttpOnly = false, // Kako bi mu mogli pristupiti iz Javascripta
ExpireTimeSpan = TimeSpan.FromDays(1),
LoginPath = PathString.Empty,
LogoutPath = PathString.Empty,
SlidingExpiration = true,
#if DEBUG
CookieSecure = CookieSecureOption.SameAsRequest,
#else
CookieSecure = CookieSecureOption.Always,
#endif
CookieDomain = "localhost"
});
and this is my token configuration
builder.Register(ctx => new OAuthAuthorizationServerOptions
{
AuthorizeEndpointPath = new PathString("/api/authorize"),
TokenEndpointPath = new PathString("/api/token"),
ApplicationCanDisplayErrors = true,
Provider = ctx.Resolve<ApplicationOAuthProvider>(),
//RefreshTokenProvider = ctx.Resolve<ApplicationRefreshTokenProvider>(),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
#if DEBUG
AllowInsecureHttp = true
#endif
});
After hosting my application on HTTPS localhost it automagicaly worked.
Why? Still don't know :P

Can we use OAuth to authenticate the consumers in my Web API?

I am developing a web application, mobile application and desktop application which all can access the data with the help of a single API which can be developed by ASP.NET Web API.
In my Web API can I authenticate the user credentials and the consumer Application key with the help of OAuth?
Can you guys guide me to achieve the same with any examples?
Add the following lines in startup class
public class Startup
{
public void Configuration(IAppBuilder app)
{
var oauthProvider = new OAuthAuthorizationServerProvider
{
OnGrantResourceOwnerCredentials = async context =>
{
IsValid = true;
//You can get the username and password by context.username and context.password
if (IsValid)
{
var claimsIdentity = new ClaimsIdentity(context.Options.AuthenticationType);
claimsIdentity.AddClaim(new Claim("user", context.UserName));
context.Validated(claimsIdentity);
return;
}
context.Rejected();
},
OnValidateClientAuthentication = async context =>
{
string clientId;
string clientSecret;
if (context.TryGetBasicCredentials(out clientId, out clientSecret))
{
if (clientId == GlobalAppSettings.SystemSettings.ApplicationKey)
{
context.Validated();
}
}
}
};
var oauthOptions = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/accesstoken"),
Provider = oauthProvider,
AuthorizationCodeExpireTimeSpan = TimeSpan.FromMinutes(1),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(3),
SystemClock = new SystemClock()
};
app.UseOAuthAuthorizationServer(oauthOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
var config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
app.UseWebApi(config);
}
}
And invoke the startup method by start up the new OAuth APP from where you need the authorization and OAuth token
You can use your own host by using the self hosting namespace.
Otherwise you can use Microsoft.Owin.Host.HttpListener namespace and host the OAuth app in different host as below
var Basesite = "http://localhost:9327/";
var homeProcessorModel = new HomeProcessorModel();
using (WebApp.Start<Startup>(url: Basesite))
{
var client = new HttpClient();
var form = new Dictionary<string, string>
{
{"grant_type","password"},
{"userName",username},
{"passWord",password}
};//If you are using grant_type as password, you have to send the username and password to OAuth protocol.
var tokenResponse = client.PostAsync(Basesite + "accesstoken", new FormUrlEncodedContent(form)).Result;
var token = tokenResponse.Content.ReadAsAsync<Token>(new[] { new JsonMediaTypeFormatter() }).Result;
//You can get the token with token.AccessToken object
}

Resources