Authentication¶
EzSCIM uses JWT Bearer token authentication (HS256). All SCIM endpoints require a valid
Authorization: Bearer <token> header.
1. Installation¶
Register the JWT token service in Program.cs:
// Register JWT token service
builder.Services.AddJwtTokenService();
// Configure JWT authentication
builder.Services.AddAuthentication()
.AddScheme<JwtBearerTokenAuthenticationOptions, JwtBearerTokenAuthenticationHandler>(
"Bearer", null);
builder.Services.AddAuthorization();
Development token endpoint
Enable a token generation endpoint for local testing:
2. Configuration¶
Secret key requirements
- Must be at least 32 characters
- Must never be committed to Git
- Use Azure Key Vault in production (see below)
3. Generate a token (development)¶
Response:
4. Use the token¶
5. Production: Azure Key Vault¶
Generate a secret key¶
Store in Key Vault¶
az keyvault secret set \
--vault-name "your-keyvault" \
--name "Jwt-SecretKey" \
--value "your-generated-secret"
Configure the application to read from Key Vault¶
Program.cs
if (!builder.Environment.IsDevelopment())
{
var keyVaultUrl = builder.Configuration["AzureKeyVault:VaultUri"];
if (!string.IsNullOrEmpty(keyVaultUrl))
{
builder.Configuration.AddAzureKeyVault(
new Uri(keyVaultUrl),
new DefaultAzureCredential());
}
}
Configure Managed Identity¶
az identity create -g your-rg -n scim-api-identity
az keyvault set-policy \
--name your-keyvault \
--object-id <MANAGED_IDENTITY_PRINCIPAL_ID> \
--secret-permissions get list
6. Configure Entra ID (Microsoft)¶
- Azure Portal → Microsoft Entra ID → Enterprise Applications
- Select your SCIM application → Provisioning → Admin Credentials
- Tenant URL:
https://your-domain.com/scim - Secret Token: paste the full JWT prefixed with
Bearer(e.g.Bearer eyJ...) - Click Test Connection
Generate a long-lived token for Entra ID
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.IdentityModel.Tokens;
var secretKey = "your-production-secret-key";
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));
var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
claims: new[]
{
new Claim(JwtRegisteredClaimNames.Sub, "scim-client"),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
},
expires: DateTime.UtcNow.AddMinutes(525600), // 1 year
signingCredentials: credentials
);
Console.WriteLine("Bearer " + new JwtSecurityTokenHandler().WriteToken(token));
Troubleshooting¶
Common authentication errors
| Symptom | Cause | Fix |
|---|---|---|
HTTP 401 on all requests |
Token missing or wrong format | Ensure Authorization: Bearer <token> header |
HTTP 403 on /scim/auth/token |
Expected in production | Generate token via CLI script |
| Token rejected | Secret mismatch between signing and validation | Verify Jwt:SecretKey config matches signing key |
| Key Vault error at startup | Managed Identity not configured | Check identity assignment and Key Vault access policy |
Security checklist¶
- Secret key is at least 32 characters
- Secret key is never committed to Git
- Secret key is stored in Azure Key Vault in production
- Managed Identity is configured for Key Vault access
- Tokens expire (60 minutes recommended in production)
- HTTPS is enforced in production
-
/scim/auth/tokenreturns403in production - JWT logs do not contain the secret key or token content