0

Am trying to create basic register and login authentication, when I run my app everything works and my swagger interface pops up, testing the register end point gives me the error below, the exception tells me that it has something to do with my token validation parameters having a null value but I don't get how that can be.

> System.ArgumentNullException: String reference not set to an instance
> of a String. (Parameter 's') at System.Text.Encoding.GetBytes(String
> s) at
> X_Change_Api.Installers.Dbinstaller.<>c__DisplayClass0_0.b__4(JwtBearerOptions x) in C:\Users\Iron
> Man\source\repos\X_Change_Api\X_Change_Api\Installers\Dbinstaller.cs:line
> 55 at
> Microsoft.Extensions.Options.ConfigureNamedOptions`1.Configure(String
> name, TOptions options) at
> Microsoft.Extensions.Options.OptionsFactory`1.Create(String name) at
> Microsoft.Extensions.Options.OptionsMonitor`1.<>c__DisplayClass11_0.b__0()
> at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode) --- End of
> stack trace from previous location where exception was thrown --- at
> System.Lazy`1.CreateValue() at System.Lazy`1.get_Value() at
> Microsoft.Extensions.Options.OptionsCache`1.GetOrAdd(String name,
> Func`1 createOptions) at
> Microsoft.Extensions.Options.OptionsMonitor`1.Get(String name) at
> Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.InitializeAsync(AuthenticationScheme
> scheme, HttpContext context) at
> Microsoft.AspNetCore.Authentication.AuthenticationHandlerProvider.GetHandlerAsync(HttpContext
> context, String authenticationScheme) at
> Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext
> context, String scheme) at
> Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext
> context) at
> Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext
> httpContext) at
> Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext
> httpContext, ISwaggerProvider swaggerProvider) at
> Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext
> context) HEADERS ======= Accept: */* Accept-Encoding: gzip, deflate,
> br Accept-Language: en-GB,en-US;q=0.9,en;q=0.8 Host: localhost:5001
> Referer: https://localhost:5001/swagger/index.html User-Agent:
> Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,
> like Gecko) Chrome/84.0.4147.105 Safari/537.36 :method: GET
> :authority: localhost:5001 :scheme: https :path:
> /api/v1/identity/Register?Email=589tghrv&Password=feufeivw&User_Name=4huivnfgi
> sec-fetch-site: same-origin sec-fetch-mode: cors sec-fetch-dest:
> empty
//Startup.cs
    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)
        {
            var instalation = typeof(Startup).Assembly.ExportedTypes.
                Where(x => typeof(IInstaller).IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract).Select(Activator.CreateInstance).Cast<IInstaller>().ToList();
            instalation.ForEach(instal => instal.Cleanner(Configuration, services));
        }

        // 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.UseSwagger();

            app.UseSwaggerUI(p => p.SwaggerEndpoint("/swagger/v1/swagger.Json", "TXC"));

            app.UseRouting();

            app.UseAuthentication();

            var Raphael = new Swagger_sett();
            Configuration.GetSection(nameof(Startup)).Bind(Raphael);

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
                
            });

            
        }
    }

//Installer class
public class In_App_Componentes : IInstaller
    {
        public void Cleanner(IConfiguration configuration, IServiceCollection services)
        {
            services.AddControllers().AddNewtonsoftJson(p => p.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver());
            services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
            services.AddScoped<IX_Change, The_center>();
            services.AddScoped<IIdentify, Identify>();
        }
    }

//Other installer class
public class Dbinstaller : IInstaller
    {
        public void Cleanner(IConfiguration configuration, IServiceCollection services)
        {
            var jwt = new Mystery();
            configuration.Bind(key:nameof(jwt), jwt);

            services.AddSingleton(jwt);

            services.AddDbContext<DataContext>(opt =>
            opt.UseSqlServer(configuration.GetConnectionString("TXC Connection")));
            services.AddIdentityCore<IdentityUser>();

            services.AddIdentity<IdentityUser, IdentityRole>(option =>
            {
                option.Password.RequireDigit = true;
                option.Password.RequireLowercase = true;
                option.Password.RequiredLength = 8;
            }).AddEntityFrameworkStores<DataContext>().AddDefaultTokenProviders();

            services.AddMvc(x =>
            {
                x.EnableEndpointRouting = false;
            }).SetCompatibilityVersion(CompatibilityVersion.Latest);

            services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
                .AddJwtBearer(x =>
                {
                    x.SaveToken = true;
                    x.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuerSigningKey = true,
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwt.Secret)),
                        ValidateIssuer = false,
                        ValidateAudience = false,
                        RequireExpirationTime = false,
                        ValidateLifetime = true
                    };
                });


            services.AddSwaggerGen(x =>
            {
                x.SwaggerDoc("v1", new OpenApiInfo { Title = "TXC API", Version = "v1" });

               
                x.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                    { 
                     Description="JWT Authorization Header using the bearer scheme",
                     Name="Authorization",
                     In=ParameterLocation.Header,
                     Type=SecuritySchemeType.ApiKey
                    });
                x.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                   {new OpenApiSecurityScheme{Reference=new OpenApiReference
                    {
                        Id="Bearer",
                        Type=ReferenceType.SecurityScheme
                    }
                   },new List<string>() }
                });
            });

        }
    }
//Register/Login controller
 [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
    public class IdentifyMe : Controller
    {
        private readonly IIdentify _identify;
        private readonly Users _member;

        public IdentifyMe(IIdentify identifying, Users users)
        {
            _identify = identifying;
            _member = users;
        }

        [HttpGet(Api_Routes.Identity.Register)]
        public async Task<IActionResult> Register(UserRegistration register)
        {
            var members = _member.Email.ToList();
            var individual = members.FirstOrDefault(x => x.Equals(register.Email)).ToString();

            if (!ModelState.IsValid)
            {
                return BadRequest(new Unauthenticated
                {
                    Errors=ModelState.Values.SelectMany(x=>x.Errors.Select(xx=>xx.ErrorMessage))
                });
            }


            var authresponce = await _identify.RegisterAsync(register.Email, register.Password, register.User_Name);

            if (!authresponce.Success)
            {
                return BadRequest(new Unauthenticated
                {
                    Errors = authresponce.Errors
                });
            }
            return Ok(new Authenticated
            {
                Token = authresponce.Token
            });
        }



        [HttpGet(Api_Routes.Identity.Login)]
        public async Task<IActionResult> LoginAsync(User_login login)
        {
            var authresponce = await _identify.LoginAsync(login.email, login.Password);

            if (!authresponce.Success)
            {
                return BadRequest(new Unauthenticated
                {
                    Errors = authresponce.Errors
                });
            }
            return Ok(new Authenticated
            {
                Token = authresponce.Token
            });
        }


    }

//Token generation class
public class Identify : IIdentify
    {
        private readonly UserManager<IdentityUser> _manager;

        private readonly Mystery _jwtset;



        public Identify(UserManager<IdentityUser> userManager, Mystery jW)
        {
            _manager = userManager;
            _jwtset = jW;
        }

       

        public async Task<Authentication_result> RegisterAsync(string email, string password, string Username)
        {
            var exists = _manager.FindByEmailAsync(email);

            if (exists != null)
            {
                return new Authentication_result
                {
                    Errors = new[] { "User with this email already exists" }
                };
            }

            var newPerson = new IdentityUser
            {
                Email = email,
                UserName = Username

            };


            var Creation = await _manager.CreateAsync(newPerson, password);

            if (!Creation.Succeeded)
            {
                return new Authentication_result
                {
                    Errors = new[] { "Invalid user!" }
                };
            }

            return Generate_Authentication_Result(newPerson);
        }

        public async Task<Authentication_result> LoginAsync(string email, string Password)
        {
            var user = await _manager.FindByEmailAsync(email);

            if (user == null)
            {
                return new Authentication_result
                {
                    Errors = new[] { "User does not exists" }
                };
            }

            var validate_password = await _manager.CheckPasswordAsync(user, Password);

            if (!validate_password)
            {
                return new Authentication_result
                {
                    Errors = new[] { "" }
                };
            }

            return Generate_Authentication_Result(user);
        }

        private Authentication_result Generate_Authentication_Result(IdentityUser newPerson)
        {
            var Tokenhandler = new JwtSecurityTokenHandler();
            var key = Encoding.ASCII.GetBytes(_jwtset.Secret);
            var TokenDescripter = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new[]
               {
                   new Claim(JwtRegisteredClaimNames.Sub, newPerson.Email),
                   new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
                   new Claim(JwtRegisteredClaimNames.Email, newPerson.Email),
                   new Claim("id",newPerson.Id)

               }),

                Expires = DateTime.UtcNow.AddHours(2),
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
            };

            var token = Tokenhandler.CreateToken(TokenDescripter);

            return new Authentication_result
            {
                Success = true,
                Token = Tokenhandler.WriteToken(token)
            };
        }
    }
  • 2
    Looks like it is this line: `IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwt.Secret))` in `DbInstaller` and the property `jwt.Secret` is null. Try setting a breakpoint and verify this. – Michael Jul 30 '20 at 22:31
  • Paste your exception message again, and use code formatting this time (using the `{}` icon in the editor window tool bar). As you can see, quoting it produces an unreadable mess. A simple edit won't work; all of the new line characters have been removed. – Robert Harvey Jul 30 '20 at 22:41
  • Ok so ironically the break point only hits when the application first runs and tries to access the weather controller that's created when a project is first created(don't know why this happens), but after that the register end point isn't being triggered. – Raphael Simfukwe Jul 30 '20 at 22:52
  • PS I deleted the weather controller and its class so not sure why its end point is still there – Raphael Simfukwe Jul 30 '20 at 22:53

1 Answers1

1

The exception tells you that jwt.Secret is null. You should check if your configuration is correct.

kkica
  • 4,034
  • 1
  • 20
  • 40
  • I did, the only thing that changed was the type of exception I was getting(500 to 401) – Raphael Simfukwe Jul 30 '20 at 23:12
  • @Raphael I think you're failing to realise that you've solved the problem you've posted about here. 500 is "Internal Server Error", which means an exception occurred internally. 401 is "Forbidden", meaning that you're not passing a valid access token to the API with your request. It's a completely separate issue. – ProgrammingLlama Jul 30 '20 at 23:51
  • Your actually right(how could l have missed that), thanks for the pointer. – Raphael Simfukwe Jul 31 '20 at 00:06