Home > Software design >  My API does not authorize it's own generated tokens
My API does not authorize it's own generated tokens

Time:03-11

I've been fighting with my API since it's not accepting my tokens. I generate the tokens via a class with its own signing key and credentials. Does anybody know what am I doing wrong and maybe this can help other members of the community?

What do I do: I ask a GET request with the generated API token. In https://danzai.pidepormi.com/products and it returns Unauthorized.

Example generated token (1 day lifetime): eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImFsZXhAbWljcm9tYXIubmV0IiwibmJmIjoxNjQ2OTExNDgxLCJleHAiOjE2NDY5OTc4ODEsImlhdCI6MTY0NjkxMTQ4MSwiaXNzIjoiZGFuemFpLW9yZGVyZm9ybWUtYXBpIiwiYXVkIjoiZGFuemFpLW9yZGVyZm9ybWUtYXBwIn0.GTGafndN-GH-45mQbktKPF7EtSI3BQkyOSkAMISSUUo

You can check the token is valid by putting it with this signature: Lnk&_sZYp@6rMgSm9Gl9vpzgO8m1?3JzpbCQ7U3y$=kR1n75*Rx6=p_$vd$aP2?7t! in https://jwt.io/

I leave the classes involved in this case:

ProductController:

[Authorize]
[HttpGet("/products")]
public async Task<ActionResult<List<Product>>> GetProducts()
{
    database = DatabaseModel.GetDatabase(configuration);
    List<Product> productsToReturn = new();
    productsToReturn = ProductMethods.GetProducts(database);
    if(productsToReturn.Count > 0)
    {
        return Ok(productsToReturn);
    }
    else if(productsToReturn.Count == 0)
    {
        return NoContent();
    }
    else
    {
        return BadRequest();
    }
}

Product class and ProductMethods:

public class Product
{
    public int id { get; set; }
    public string name { get; set; }
    public string description { get; set; }
    public string image_url { get; set; }
    public bool available { get; set; } 
    public string family_name { get; set; }
    public string subfamily_name { get; set; }
    public List<Supplier> suppliers { get; set; }
    public Supplier selectedSupplier { get; set; }
}

public static class ProductMethods
{
    public static List<Product> GetProducts(IDataBase database)
    {
        try
        {
            List<Product> productsToReturn = new();
            database.StartTransaction();
            string SQLText = "SELECT * FROM OBTENERPRODUCTOS";
            FbCommand SQLCommand = new FbCommand();
            SQLCommand.CommandText = SQLText;
            DataTable dataTableProducts = database.Select(SQLCommand);
            database.CommitTransaction();
            if (dataTableProducts.Rows.Count > 0)
            {
                foreach (DataRow dataRowProducts in dataTableProducts.Rows)
                {
                    Product productToAdd = new();
                    Supplier supplierToAdd = new();
                    if (dataRowProducts["CODIGO"] != DBNull.Value) productToAdd.id = Convert.ToInt32(dataRowProducts["CODIGO"]);
                    if (dataRowProducts["DESCRIPCION"] != DBNull.Value) productToAdd.description = Convert.ToString(dataRowProducts["DESCRIPCION"]);
                    if (dataRowProducts["PRECIO"] != DBNull.Value) supplierToAdd.price = Convert.ToDouble(dataRowProducts["PRECIO"]);
                    if (dataRowProducts["NOMBRE_FAMILIA"] != DBNull.Value) productToAdd.family_name = Convert.ToString(dataRowProducts["NOMBRE_FAMILIA"]);
                    if (dataRowProducts["NOMBRE_SUBFAMILIA"] != DBNull.Value) productToAdd.subfamily_name = Convert.ToString(dataRowProducts["NOMBRE_SUBFAMILIA"]);
                    if (dataRowProducts["URL_IMAGEN"] != DBNull.Value) productToAdd.image_url = Convert.ToString(dataRowProducts["URL_IMAGEN"]);
                    if (dataRowProducts["ID_PROVEEDOR"] != DBNull.Value) supplierToAdd.id = Convert.ToInt32(dataRowProducts["ID_PROVEEDOR"]);
                    if (dataRowProducts["NOMBRE_PROVEEDOR"] != DBNull.Value) supplierToAdd.name = Convert.ToString(dataRowProducts["NOMBRE_PROVEEDOR"]);
                    if (dataRowProducts["ACTIVO"] != DBNull.Value) supplierToAdd.active = Convert.ToBoolean(dataRowProducts["ACTIVO"]);
                    productToAdd.suppliers.Add(supplierToAdd);
                    productsToReturn.Add(productToAdd);
                }
                return productsToReturn;
            }
            else
            {
                return productsToReturn;
            }
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine(ex.Message);
            Console.Error.WriteLine(ex.InnerException);
            database.RollBackTransaction();
            throw;
        }
    }
}

AuthenticatedUser class:

    public class AuthenticatedUser : IIdentity
    {
        public AuthenticatedUser(string authenticateType, bool isAuthenticated, string email)
        {
            AuthenticationType = authenticateType;
            IsAuthenticated = isAuthenticated;
            Name = email;
        }

        public string AuthenticationType { get; }

        public bool IsAuthenticated { get; }

        public string Name { get; }
    }
}

Token class:

public class Token
{
    public Token() { }
    public string token { get; set; }
    public DateTime expires { get; set; }
}

JwtToken class:

public class JwtToken
{
    private const string SECRET_KEY = "Lnk&_sZYp@6rMgSm9Gl9vpzgO8m1?3JzpbCQ7U3y$=kR1n75*Rx6=p_$vd$aP2?7t!";
    public static readonly SymmetricSecurityKey SIGNING_KEY = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SECRET_KEY));
    public static Token GenerateJwtToken(string email)
    {
        SigningCredentials credentials = new SigningCredentials(SIGNING_KEY, SecurityAlgorithms.HmacSha256);
        AuthenticatedUser authenticatedUser = new(JwtBearerDefaults.AuthenticationScheme, true, email);
        SecurityTokenDescriptor securityTokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(authenticatedUser),
            Issuer = "danzai-orderforme-api",
            Audience = "danzai-orderforme-app",
            IssuedAt = DateTime.UtcNow,
            SigningCredentials = credentials,
            Expires = DateTime.UtcNow.AddMinutes(1440),
        };
        JwtSecurityTokenHandler securityTokenHandler = new JwtSecurityTokenHandler();
        SecurityToken securityToken = securityTokenHandler.CreateToken(securityTokenDescriptor);
        string tokenString = securityTokenHandler.WriteToken(securityToken);
        Token tokenToReturn = new();
        tokenToReturn.token = tokenString;
        tokenToReturn.expires = securityToken.ValidTo;
        return tokenToReturn;
    }

    public static string ReadTokenUser(String accessToken)
    {
        var tokenHandler = new JwtSecurityTokenHandler();
        if (accessToken.Contains("Bearer ")) accessToken = accessToken.Split(' ')[1];
        var token = tokenHandler.ReadToken(accessToken) as JwtSecurityToken;
        string email = token.Claims.First(claim => claim.Type == "unique_name").Value;
        return email;
    }
}

And finally Program class:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
StartupUtils.CopyAppSettings(args[0]);
string SECRET_KEY = "Lnk&_sZYp@6rMgSm9Gl9vpzgO8m1?3JzpbCQ7U3y$=kR1n75*Rx6=p_$vd$aP2?7t!";
SymmetricSecurityKey SIGNING_KEY = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SECRET_KEY));

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = "JwtBearer";
    options.DefaultChallengeScheme = "JwtBearer";
})
.AddJwtBearer("JwtBearer", jwtOptions =>
{
    jwtOptions.TokenValidationParameters = new TokenValidationParameters()
    {
        IssuerSigningKey = SIGNING_KEY,
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidIssuer = "danzai-orderforme-api",
        ValidAudience = "danzai-orderforme-app",
        RequireSignedTokens = true,
        ClockSkew = TimeSpan.Zero
    };
});
builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo { Title = "danzai-orderforme_api", Version = "v1" });
    c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
    {
        Description = "Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
        Name = "Authorization",
        In = ParameterLocation.Header,
        Type = SecuritySchemeType.ApiKey,
        Scheme = "bearer",
        BearerFormat = "JWT"
    });
    c.AddSecurityRequirement(new OpenApiSecurityRequirement
    {
        {
            new OpenApiSecurityScheme
            {
                Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }
            },
            new List<string>()
        }
    });
});

var app = builder.Build();

app.UseCors(options =>
{
    //string[] allowedOrigins = { "*" };
    //options.WithOrigins(allowedOrigins);
    options.AllowAnyMethod();
    options.AllowAnyHeader();
    options.AllowCredentials();
    options.SetIsOriginAllowed(origin => true);
});

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();
app.UseAuthentication();

app.MapControllers();

app.Run();

CodePudding user response:

You just have to change line order for:

app.UseAuthorization();
app.UseAuthentication();

TO

app.UseAuthentication();
app.UseAuthorization();

That will work.

  • Related