Skip to main content
Chargeworx uses IdentityServer4 for API authentication and authorization via OAuth2 and OpenID Connect.

Authentication flows

Client credentials flow

Service-to-service authentication for API access:
  1. Client registration: Register client in IdentityServerClient table
  2. Token request: Request access token with client credentials
  3. Token validation: API validates token signature and claims
  4. Scope authorization: Check token scopes against endpoint requirements
Token request:
curl -X POST "https://api.chargeworx.com/connect/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=your_client_id" \
  -d "client_secret=your_client_secret" \
  -d "scope=AdminUIScope"
Token response:
{
  "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "AdminUIScope"
}
API call with token:
curl -X GET "https://api.chargeworx.com/api/admin/companies" \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6..."

Scopes

AdminUIScope

Full administrative access to all API endpoints:
  • Company and project management
  • User management
  • Transaction queries
  • Report generation
  • Background process monitoring
  • System configuration
Endpoints: /api/admin/*

PaymentScope

Limited access for payment processing:
  • Transaction creation (authorize, capture, refund, void)
  • Payment info queries
  • Chargeback notifications
Endpoints: /api/payment/*

InternalScope

Internal system operations:
  • Payflow webhook callbacks
  • Background process execution
  • System health checks
Endpoints: /api/internal/*

Client management

Client registration

Clients are stored in the IdentityServerClient table:
public class IdentityServerClient
{
    public Guid Id { get; set; }
    public string ClientId { get; set; }
    public string ClientSecret { get; set; } // Hashed
    public string ClientName { get; set; }
    public List<string> AllowedScopes { get; set; }
    public int AccessTokenLifetime { get; set; } // Seconds
    public bool Enabled { get; set; }
    public DateTime? ExpirationDate { get; set; }
    public DateTime DateCreated { get; set; }
}

Client secret rotation

Clients support key rotation for security:
  1. Generate new secret: Create new client secret
  2. Update client: Store new secret hash
  3. Notify client: Send notification with new secret
  4. Grace period: Old secret remains valid for transition
  5. Deactivate old secret: Remove old secret after grace period
Expiration notifications:
  • 30 days before expiration
  • 7 days before expiration
  • On expiration day

Client scopes

Clients can have multiple scopes:
{
  "clientId": "admin-portal",
  "allowedScopes": ["AdminUIScope", "PaymentScope"]
}

Token validation

JWT structure

Tokens are signed JWTs with the following claims:
{
  "iss": "https://api.chargeworx.com",
  "aud": "chargeworx-api",
  "client_id": "admin-portal",
  "scope": ["AdminUIScope"],
  "exp": 1640995200,
  "iat": 1640991600,
  "nbf": 1640991600
}

Signature validation

Tokens are signed with RSA256:
  1. Public key retrieval: Get public key from /.well-known/openid-configuration/jwks
  2. Signature verification: Verify token signature with public key
  3. Claims validation: Validate issuer, audience, expiration
  4. Scope validation: Check required scopes for endpoint

Token caching

Validated tokens are cached for performance:
  • Cache key: Token hash
  • Cache duration: Token lifetime
  • Cache invalidation: On client deactivation

Authorization policies

Scope-based authorization

Controllers use scope-based authorization:
[Authorize(Policy = "AdminUIScope")]
[ApiController]
[Route("api/admin/companies")]
public class CompanyController : BaseAdminController
{
    // Admin endpoints
}
[Authorize(Policy = "PaymentScope")]
[ApiController]
[Route("api/payment/transactions")]
public class TransactionPaymentController : BasePaymentController
{
    // Payment endpoints
}

Policy configuration

Policies are configured in Startup.cs:
services.AddAuthorization(options =>
{
    options.AddPolicy("AdminUIScope", policy =>
        policy.RequireClaim("scope", "AdminUIScope"));
    
    options.AddPolicy("PaymentScope", policy =>
        policy.RequireClaim("scope", "PaymentScope"));
    
    options.AddPolicy("InternalScope", policy =>
        policy.RequireClaim("scope", "InternalScope"));
});

Security considerations

Client secrets

  • Hashing: Secrets are hashed with SHA256 before storage
  • Transmission: Secrets are transmitted over HTTPS only
  • Storage: Never log or display secrets in plain text
  • Rotation: Rotate secrets every 90 days

Token security

  • Lifetime: Tokens expire after 1 hour (configurable)
  • Refresh: No refresh tokens (use client credentials for new token)
  • Revocation: Tokens cannot be revoked (short lifetime mitigates risk)
  • Scope limitation: Request minimum required scopes

IP whitelisting

Additional security via IP whitelisting:
public class WhitelistIp
{
    public Guid Id { get; set; }
    public Guid CompanyProjectId { get; set; }
    public string IpAddress { get; set; }
    public string Description { get; set; }
    public bool IsActive { get; set; }
}
Requests are validated against whitelist before token validation.

Configuration

IdentityServer configuration

{
  "IdentityServerConfiguration": {
    "Authority": "https://api.chargeworx.com",
    "ApiName": "chargeworx-api",
    "ApiSecret": "your_api_secret",
    "RequireHttpsMetadata": true,
    "AccessTokenLifetime": 3600,
    "SigningKeyPath": "/keys/signing-key.pfx",
    "SigningKeyPassword": "your_key_password"
  }
}

Signing key management

Signing keys are stored in the Key database:
  • Key rotation: Rotate signing keys every 90 days
  • Key storage: Store keys in Key table with encryption
  • Key retrieval: Load keys on application startup
  • Key validation: Validate key expiration on each token issuance

Discovery endpoint

IdentityServer exposes discovery endpoint at /.well-known/openid-configuration:
{
  "issuer": "https://api.chargeworx.com",
  "jwks_uri": "https://api.chargeworx.com/.well-known/openid-configuration/jwks",
  "token_endpoint": "https://api.chargeworx.com/connect/token",
  "grant_types_supported": ["client_credentials"],
  "scopes_supported": ["AdminUIScope", "PaymentScope", "InternalScope"],
  "token_endpoint_auth_methods_supported": ["client_secret_post"]
}

Testing

Test clients

Development environment includes test clients:
{
  "clientId": "test-admin",
  "clientSecret": "test-secret",
  "allowedScopes": ["AdminUIScope"]
}

Token generation

Generate test tokens via Swagger UI or curl:
# Get token
TOKEN=$(curl -X POST "https://localhost:5001/connect/token" \
  -d "grant_type=client_credentials" \
  -d "client_id=test-admin" \
  -d "client_secret=test-secret" \
  -d "scope=AdminUIScope" \
  | jq -r '.access_token')

# Use token
curl -X GET "https://localhost:5001/api/admin/companies" \
  -H "Authorization: Bearer $TOKEN"