From dbc4d973f9d70fe25f6a755896888701e7fab73a Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Mon, 21 Jul 2025 16:41:06 -0700 Subject: [PATCH] consolidate jwt settings and setup docker compose --- .env_Template | 27 +++++++++++++--- docker-compose.yml | 5 +-- .../Controllers/AuthenticationController.cs | 5 +-- src/Server/Program.cs | 21 ++++++++---- src/Server/Services/jwt.cs | 32 +++++++++++-------- 5 files changed, 60 insertions(+), 30 deletions(-) diff --git a/.env_Template b/.env_Template index 98f082d..dee9450 100755 --- a/.env_Template +++ b/.env_Template @@ -1,13 +1,32 @@ -Payment_Service=StripeIntent # Options are [ StripeIntent ] +############# +## Payment ## +############# +# Options are [ StripeIntent ] +Payment_Service=StripeIntent + +# StripeIntent Options Stripe_PublicKey= Stripe_PublicKey= Stripe_Endpoint_Secret= -MySQL_Server=mistox-database +#################### +## Authentication ## +#################### + +# Random secret token for encrypting JWT contents +JWT_Secret= + +############## +## Database ## +############## + MySQL_User=root -MySQL_Database=mistox -MySQL_Pass=oasv34$8gpv023dd # Random value for the server and MySQL to communicate with +MySQL_Pass=oasv34$8gpv023dd + +############## +## Email ## +############## Email_Server= # Hostname of email server Email_Port= # SMTP port used diff --git a/docker-compose.yml b/docker-compose.yml index 3ec7754..4098a89 100755 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,18 +5,19 @@ services: image: docker.mistox.net/boredcareers-website:latest restart: always environment: + - MySQLServer=boredcareers-database + - MySQLDatabase=boredcareers - PaymentService=${Payment_Service} - StripePublicKey=${Stripe_PublicKey} - StripeApiKey=${Stripe_ApiKey} - StripeEndpointSecret=&{Stripe_Endpoint_Secret} - - MySQLServer=${MySQL_Server} - MySQLUser=${MySQL_User} - MySQLPass=${MySQL_Pass} - - MySQLDatabase=${MySQL_Database} - EmailServer=${Email_Server} - EmailPort=${Email_Port} - EmailAddress=${Email_Address} - EmailPassword=${Email_Password} + - JWTsecret=${JWT_Secret} ports: - 5000:5000 depends_on: diff --git a/src/Server/Controllers/AuthenticationController.cs b/src/Server/Controllers/AuthenticationController.cs index 0c2bc5c..81fcf06 100755 --- a/src/Server/Controllers/AuthenticationController.cs +++ b/src/Server/Controllers/AuthenticationController.cs @@ -1,7 +1,4 @@ -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Authentication.Cookies; -using Microsoft.AspNetCore.Mvc; -using System.Security.Claims; +using Microsoft.AspNetCore.Mvc; using BoredCareers.Services; using BoredCareers.Services.DatabaseService; using BoredCareers.Entities; diff --git a/src/Server/Program.cs b/src/Server/Program.cs index fdc9bc3..3109476 100755 --- a/src/Server/Program.cs +++ b/src/Server/Program.cs @@ -1,4 +1,3 @@ -using Microsoft.AspNetCore.Authentication.Cookies; using BoredCareers.Controllers.Payment; using BoredCareers.Services; using BoredCareers.Services.DatabaseService; @@ -7,7 +6,6 @@ using Stripe; using System.Security.Claims; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; -using Org.BouncyCastle.Bcpg.Sig; using System.Text; using System.IdentityModel.Tokens.Jwt; @@ -41,6 +39,15 @@ string dbPass = !string.IsNullOrEmpty(_dbpass) ? _dbpass : "oasv34$8gpv023dd"; DatabaseService databaseService = new DatabaseService(connectionString: "server=" + dbserver + ";user=" + dbUser + ";database=" + dbdatabase + ";password=" + dbPass + ";port=3306;"); builder.Services.Add( new ServiceDescriptor( typeof( DatabaseService ), databaseService ) ); +//////////////////////////////// +////////// Auth Service //////// +//////////////////////////////// + +// Address +string? _jwtSecret = Environment.GetEnvironmentVariable("JWTsecret"); +string JWTsecret = !string.IsNullOrEmpty(_jwtSecret) ? _jwtSecret : "v0Ftluhdh7Nht8^2b5eaiC^IS^VS1ku0VBs3j*B2"; +BoredCareersJWT.TokenSecretKey = JWTsecret; + //////////////////////////////// ///////// Email Service //////// //////////////////////////////// @@ -95,14 +102,14 @@ builder.Services.AddAuthentication(options => { ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, - ValidIssuer = "your-app", - ValidAudience = "your-app", - IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("secret-key")), + ValidIssuer = BoredCareersJWT.TokenIssuer, + ValidAudience = BoredCareersJWT.TokenAudience, + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(BoredCareersJWT.TokenSecretKey)), ClockSkew = TimeSpan.FromMinutes(1) }; options.Events = new JwtBearerEvents { OnMessageReceived = context => { - context.Token = context.Request.Cookies["access_token"]; + context.Token = context.Request.Cookies[BoredCareersJWT.TokenName]; return Task.CompletedTask; }, OnTokenValidated = context => { @@ -110,7 +117,7 @@ builder.Services.AddAuthentication(options => { if (jwtToken != null) { var exp = jwtToken.ValidTo; var now = DateTime.UtcNow; - if ((exp - now) < TimeSpan.FromMinutes(5)) { + if ((exp - now) < TimeSpan.FromDays(3)) { int accountID = Convert.ToInt32(context.Principal?.FindFirst(ClaimTypes.NameIdentifier)?.Value); bool isPersistent = bool.Parse(context.Principal?.FindFirst(ClaimTypes.IsPersistent)?.Value); var newJWT = BoredCareersJWT.GenereateJWTToken(accountID, isPersistent); diff --git a/src/Server/Services/jwt.cs b/src/Server/Services/jwt.cs index 4d1a03c..5fe00de 100644 --- a/src/Server/Services/jwt.cs +++ b/src/Server/Services/jwt.cs @@ -1,26 +1,33 @@ using System.IdentityModel.Tokens.Jwt; +using System.Runtime.CompilerServices; using System.Security.Claims; using System.Text; using Microsoft.IdentityModel.Tokens; namespace BoredCareers.Services { public class BoredCareersJWT { + + public static string TokenAudience = "https://boredcareers.com/api"; + public static string TokenIssuer = "https://boredcareers.com"; + public static string TokenSecretKey = ""; + public static string TokenName = "mistox_session"; + public static string GenereateJWTToken(int accountID, bool StayLoggedIn) { var tokenHandler = new JwtSecurityTokenHandler(); - var key = Encoding.UTF8.GetBytes("your-super-secret-key"); + var key = Encoding.UTF8.GetBytes(TokenSecretKey); var tokenDiscriptor = new SecurityTokenDescriptor { - Subject = new ClaimsIdentity(new[] { + Subject = new ClaimsIdentity([ new Claim(ClaimTypes.NameIdentifier, accountID.ToString()), new Claim(ClaimTypes.IsPersistent, StayLoggedIn.ToString()) - }), - Expires = DateTime.UtcNow.AddMinutes(15), + ]), + Expires = DateTime.UtcNow.AddDays(7), IssuedAt = DateTime.UtcNow, - SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.RsaSha512), - Audience = "your-app", - Issuer = "your-app" + SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256), + Audience = TokenAudience, + Issuer = TokenIssuer }; var token = tokenHandler.CreateToken(tokenDiscriptor); @@ -30,16 +37,15 @@ namespace BoredCareers.Services { public static void SignIn(HttpResponse Response, bool StayLoggedIn, string jwt) { if (StayLoggedIn) { // Stay logged in cookie - Response.Cookies.Append("access_token", jwt, new CookieOptions { + Response.Cookies.Append(TokenName, jwt, new CookieOptions { Secure = true, HttpOnly = true, SameSite = SameSiteMode.Strict, - Expires = DateTime.UtcNow.AddMinutes(15) + Expires = DateTime.UtcNow.AddDays(7) }); - } - else { + } else { // Session cookie - Response.Cookies.Append("access_token", jwt, new CookieOptions { + Response.Cookies.Append(TokenName, jwt, new CookieOptions { Secure = true, HttpOnly = true, SameSite = SameSiteMode.Strict, @@ -48,7 +54,7 @@ namespace BoredCareers.Services { } public static void SignOut(HttpResponse Response) { - Response.Cookies.Delete("access_token"); + Response.Cookies.Delete(TokenName); } } } \ No newline at end of file