c# - example - Obteniendo "error": "unsupported_grant_type" al intentar obtener un JWT llamando a una API web segura de OWIN OAuth a través de Postman
web api authentication example (8)
-
Tenga en cuenta la URL:
localhost:55828/token
(nolocalhost:55828/API/token
) -
Tenga en cuenta los datos de la solicitud.
No está en formato json, solo son datos simples sin comillas dobles.
[email protected]&password=Test123$&grant_type=password
- Tenga en cuenta el tipo de contenido. Tipo de contenido: ''application / x-www-form-urlencoded'' (no Content-Type: ''application / json'')
-
Cuando usa JavaScript para realizar una solicitud de publicación, puede usar lo siguiente:
$http.post("localhost:55828/token", "userName=" + encodeURIComponent(email) + "&password=" + encodeURIComponent(password) + "&grant_type=password", {headers: { ''Content-Type'': ''application/x-www-form-urlencoded'' }} ).success(function (data) {//...
Vea las capturas de pantalla a continuación de Postman:
He seguido este artículo para implementar un servidor de autorización de OAuth. Sin embargo, cuando uso post man para obtener un token, recibo un error en la respuesta:
"error": "unsupported_grant_type"
Leí en alguna parte que los datos en Postman deben publicarse usando
Content-type:application/x-www-form-urlencoded
.
He preparado la configuración requerida en Cartero:
y aun así mis encabezados son así:
Aqui esta mi codigo
public class CustomOAuthProvider : OAuthAuthorizationServerProvider
{
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
return Task.FromResult<object>(null);
}
public override Task MatchEndpoint(OAuthMatchEndpointContext context)
{
if (context.OwinContext.Request.Method == "OPTIONS" && context.IsTokenEndpoint)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Methods", new[] { "POST" });
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "accept", "authorization", "content-type" });
context.OwinContext.Response.StatusCode = 200;
context.RequestCompleted();
return Task.FromResult<object>(null);
}
return base.MatchEndpoint(context);
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
string allowedOrigin = "*";
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "Content-Type" });
Models.TheUser user = new Models.TheUser();
user.UserName = context.UserName;
user.FirstName = "Sample first name";
user.LastName = "Dummy Last name";
ClaimsIdentity identity = new ClaimsIdentity("JWT");
identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
foreach (string claim in user.Claims)
{
identity.AddClaim(new Claim("Claim", claim));
}
var ticket = new AuthenticationTicket(identity, null);
context.Validated(ticket);
}
}
public class CustomJwtFormat : ISecureDataFormat<AuthenticationTicket>
{
private readonly string _issuer = string.Empty;
public CustomJwtFormat(string issuer)
{
_issuer = issuer;
}
public string Protect(AuthenticationTicket data)
{
string audienceId = ConfigurationManager.AppSettings["AudienceId"];
string symmetricKeyAsBase64 = ConfigurationManager.AppSettings["AudienceSecret"];
var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64);
var signingKey = new HmacSigningCredentials(keyByteArray);
var issued = data.Properties.IssuedUtc;
var expires = data.Properties.ExpiresUtc;
var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingKey);
var handler = new JwtSecurityTokenHandler();
var jwt = handler.WriteToken(token);
return jwt;
}
public AuthenticationTicket Unprotect(string protectedText)
{
throw new NotImplementedException();
}
}
En la clase CustomJWTFormat anterior solo se alcanza el punto de interrupción en el constructor. En la clase CustomOauth, el punto de interrupción en el método GrantResourceOwnerCredentials nunca se ve afectado. Los otros lo hacen.
La clase de inicio:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
ConfigureOAuthTokenGeneration(app);
ConfigureOAuthTokenConsumption(app);
app.UseWebApi(config);
}
private void ConfigureOAuthTokenGeneration(IAppBuilder app)
{
var OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
//For Dev enviroment only (on production should be AllowInsecureHttp = false)
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/oauth/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new CustomOAuthProvider(),
AccessTokenFormat = new CustomJwtFormat(ConfigurationManager.AppSettings["Issuer"])
};
// OAuth 2.0 Bearer Access Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
}
private void ConfigureOAuthTokenConsumption(IAppBuilder app)
{
string issuer = ConfigurationManager.AppSettings["Issuer"];
string audienceId = ConfigurationManager.AppSettings["AudienceId"];
byte[] audienceSecret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["AudienceSecret"]);
// Api controllers with an [Authorize] attribute will be validated with JWT
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new[] { audienceId },
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
{
new SymmetricKeyIssuerSecurityTokenProvider(issuer, audienceSecret)
}
});
}
}
¿Debo configurar
Content-type:application/x-www-form-urlencoded
en otro lugar del código de la API web?
¿Qué podría estar mal?
Por favor ayuda.
Con Cartero, seleccione la pestaña Cuerpo y elija la opción sin formato y escriba lo siguiente:
grant_type=password&username=yourusername&password=yourpassword
La respuesta llega un poco tarde, pero en caso de que alguien tenga el problema en el futuro ...
De la captura de pantalla anterior, parece que está agregando los datos de la URL (nombre de usuario, contraseña, tipo de concesión) al encabezado y no al elemento del cuerpo.
Al hacer clic en la pestaña del cuerpo y luego seleccionar el botón de opción "x-www-form-urlencoded", debe haber una lista de valores clave debajo de donde puede ingresar los datos de la solicitud
Pregunta anterior, pero para
angular 6
, esto debe hacerse cuando está utilizando
HttpClient
Estoy exponiendo los datos de token públicamente aquí, pero sería bueno si se accede a través de propiedades de solo lectura.
import { Injectable } from ''@angular/core'';
import { HttpClient } from ''@angular/common/http'';
import { Observable, of } from ''rxjs'';
import { delay, tap } from ''rxjs/operators'';
import { Router } from ''@angular/router'';
@Injectable()
export class AuthService {
isLoggedIn: boolean = false;
url = "token";
tokenData = {};
username = "";
AccessToken = "";
constructor(private http: HttpClient, private router: Router) { }
login(username: string, password: string): Observable<object> {
let model = "username=" + username + "&password=" + password + "&grant_type=" + "password";
return this.http.post(this.url, model).pipe(
tap(
data => {
console.log(''Log In succesful'')
//console.log(response);
this.isLoggedIn = true;
this.tokenData = data;
this.username = data["username"];
this.AccessToken = data["access_token"];
console.log(this.tokenData);
return true;
},
error => {
console.log(error);
return false;
}
)
);
}
}
Si está utilizando AngularJS, debe pasar los parámetros del cuerpo como una cadena:
factory.getToken = function(person_username) {
console.log(''Getting DI Token'');
var url = diUrl + "/token";
return $http({
method: ''POST'',
url: url,
data: ''grant_type=password&[email protected]&password=mypass'',
responseType:''json'',
headers: { ''Content-Type'': ''application/x-www-form-urlencoded'' }
});
};
También recibí este error y la razón terminó siendo una URL de llamada incorrecta. Dejo esta respuesta aquí, si alguien más mezcla las URL y obtiene este error. Me tomó horas darme cuenta de que tenía una URL incorrecta.
Error que obtuve (código HTTP 400):
{
"error": "unsupported_grant_type",
"error_description": "grant type not supported"
}
Yo estaba llamando:
https://MY_INSTANCE.lightning.force.com
Mientras que la URL correcta habría sido:
intenta agregar esto en tu carga útil
grant_type=password&username=pippo&password=pluto