Client JWT authentication (#723)

## Description:

Send JWT to the game server for verification.

## Please complete the following:

- [x] I have added screenshots for all UI updates
- [ ] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
- [x] I understand that submitting code with bugs that could have been
caught through manual testing blocks releases and new features for all
contributors

---------

Co-authored-by: Scott Anderson <662325+scottanderson@users.noreply.github.com>
This commit is contained in:
Scott Anderson
2025-05-12 14:51:40 -04:00
committed by GitHub
parent b402a3549e
commit f8a052a6ce
16 changed files with 123 additions and 20 deletions
+30 -1
View File
@@ -1,3 +1,5 @@
import { JWK } from "jose";
import { z } from "zod";
import {
Difficulty,
Duos,
@@ -24,7 +26,35 @@ import { Config, GameEnv, NukeMagnitude, ServerConfig, Theme } from "./Config";
import { pastelTheme } from "./PastelTheme";
import { pastelThemeDark } from "./PastelThemeDark";
const JwksSchema = z.object({
keys: z
.object({
alg: z.literal("EdDSA"),
crv: z.literal("Ed25519"),
kty: z.literal("OKP"),
x: z.string(),
})
.array()
.min(1),
});
export abstract class DefaultServerConfig implements ServerConfig {
private publicKey: JWK;
abstract jwtAudience(): string;
jwtIssuer(): string {
const audience = this.jwtAudience();
return audience === "localhost"
? "http://localhost:8787"
: `https://api.${audience}`;
}
async jwkPublicKey(): Promise<JWK> {
if (this.publicKey) return this.publicKey;
const jwksUrl = this.jwtIssuer() + "/.well-known/jwks.json";
const response = await fetch(jwksUrl);
const jwks = JwksSchema.parse(await response.json());
this.publicKey = jwks.keys[0];
return this.publicKey;
}
otelEnabled(): boolean {
return Boolean(
this.otelEndpoint() && this.otelUsername() && this.otelPassword(),
@@ -70,7 +100,6 @@ export abstract class DefaultServerConfig implements ServerConfig {
}
abstract numWorkers(): number;
abstract env(): GameEnv;
abstract discordRedirectURI(): string;
turnIntervalMs(): number {
return 100;
}