Prep the oven and dish: Heat the oven to 375°F (190°C). Grease a 9x13-inch baking dish with nonstick spray or butter.
Slice the potatoes: Peel and slice the potatoes about 1/8-inch thick.
Thinner slices cook more evenly. Pat dry with paper towels to remove excess moisture.
Sauté aromatics: In a medium saucepan over medium heat, melt the butter. Add the onion and a pinch of salt.
Cook 4–5 minutes until soft. Stir in garlic and cook 30 seconds.
Make the roux: Sprinkle in the flour and stir for 1 minute to cook off the raw taste. The mixture will look pasty.
Build the sauce: Slowly whisk in the milk and chicken broth (if using).
Keep whisking until smooth and slightly thickened, 3–5 minutes.
Season and add cheese: Stir in Dijon, thyme, smoked paprika, 1 teaspoon salt, and 1/2 teaspoon black pepper. Remove from heat and whisk in 1 1/2 cups cheddar and the mozzarella until melted and silky.
Layer the casserole: Spread a thin layer of sauce on the bottom of the dish. Add half the potatoes, half the ham, and a light sprinkle of salt and pepper.
Pour over half the sauce. Repeat with remaining potatoes, ham, and sauce.
Top with cheese: Sprinkle the remaining 1/2 cup cheddar over the top. For extra color, dust lightly with smoked paprika.
Cover and bake: Cover tightly with foil and bake for 35 minutes to steam the potatoes.
Uncover and finish: Remove the foil and bake another 20–25 minutes, until the top is golden and the potatoes are tender when pierced with a knife.
Rest and garnish: Let the casserole rest 10 minutes to set.
Sprinkle with parsley or chives before serving.