using System.Text.Json; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Diagnostics.HealthChecks; using ProofOfConcept.Models; using ProofOfConcept.Services; using ProofOfConcept.Utilities; var builder = WebApplication.CreateSlimBuilder(args); // Load static web assets manifest (referenced libs + your wwwroot) builder.WebHost.UseStaticWebAssets(); // builder.Services.ConfigureHttpJsonOptions(options => { options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default); }); // Add services builder.Services.AddOpenApi(); builder.Services.AddMediator(); builder.Services.AddMemoryCache(); builder.Services.AddHybridCache(); builder.Services.AddHttpClient(); builder.Services.AddRazorPages(); builder.Services.AddHealthChecks() .AddAsyncCheck("", cancellationToken => Task.FromResult(HealthCheckResult.Healthy()), ["ready"]); //TODO: Check tag builder.Services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; }) .AddCookie() .AddOpenIdConnect(options => { options.Authority = "https://fleet-auth.prd.vn.cloud.tesla.com/oauth2/v3"; // Tesla auth options.ClientId = "b2240ee4-332a-4252-91aa-bbcc24f78fdb"; options.ClientSecret = "ta-secret.YG+XSdlvr6Lv8U-x"; options.ResponseType = "code"; options.SaveTokens = true; // access_token, refresh_token in auth ticket options.CallbackPath = new PathString("/token-exchange"); options.Scope.Add("openid"); options.Scope.Add("offline_access"); options.Scope.Add("vehicle_device_data"); options.Scope.Add("vehicle_location"); options.AdditionalAuthorizationParameters.Add("prompt_missing_scopes", "true"); options.AdditionalAuthorizationParameters.Add("require_requested_scopes", "true"); options.AdditionalAuthorizationParameters.Add("show_keypair_step", "true"); // PKCE, state, nonce are handled automatically }); // Add own services builder.Services.AddSingleton(); builder.Services.AddTransient(); // Add hosted services builder.Services.AddHostedService(); builder.Services.AddHostedService(); //Build app WebApplication app = builder.Build(); if (app.Environment.IsDevelopment()) { app.MapOpenApi(); app.MapGet("/GetPartnerAuthenticationToken", ([FromServices] TeslaAuthenticatorService service) => service.GetPartnerAuthenticationTokenAsync()); app.MapGet("/PartnerToken", ([FromQueryAttribute] string json, [FromServices] IMemoryCache memoryCache) => { var serializerOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true, PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower }; Token? token = JsonSerializer.Deserialize(json, serializerOptions); if (token is not null) memoryCache.Set(Keys.TeslaPartnerToken, token, token.Expires.Subtract(TimeSpan.FromSeconds(5))); return JsonSerializer.Serialize(token, new JsonSerializerOptions() { WriteIndented = true }); }); app.MapGet("/CheckRegisteredApplication", ([FromServices] TeslaAuthenticatorService service) => service.CheckApplicationRegistrationAsync()); app.MapGet("/RegisterApplication", ([FromServices] TeslaAuthenticatorService service) => service.RegisterApplicationAsync()); app.MapGet("/Authorize", (async context => await context.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties { RedirectUri = "/" }))); app.MapGet("/KeyPairing", () => Results.Redirect("https://tesla.com/_ak/developer-domain.com")); } //Map static assets app.MapStaticAssets(); //TODO: Build a middleware that responds with 503 if the public key is not registered at Tesla app.MapRazorPages(); app.Run();