Security
Security in Portway is layered: tokens decide who gets in, scopes and environments decide what they can reach, and network rules decide where requests may go.
Note
Treat this page as a starting point rather than a policy. Align it with your organisation's security policies before exposing Portway to production traffic.
Authentication
All API requests require a Bearer token:
Authorization: Bearer your-token-hereTokens are generated using cryptographically secure random values and stored encrypted on disk. Each token is bound to a username for audit trail purposes.
First-run token
On first run, Portway generates an initial token and writes it to tokens/YOUR_SERVER_NAME.txt. The token generator reference shows the file format and the fields it carries.
Caution
This file is highly sensitive: it carries a token with full scope and environment access. Remove it from disk immediately after recording the token somewhere secure. Use the Web UI to manage all subsequent tokens.
Authorization
Scope control
Restrict a token to specific endpoints using the AllowedScopes field:
| Pattern | Access |
|---|---|
* |
All endpoints |
Products,Orders |
Named endpoints only |
Product* |
All endpoints matching the prefix |
Company/Employees |
Specific namespaced endpoint |
Company/* |
All endpoints in a namespace |
GET:Products |
Single endpoint, single method |
Environment control
Restrict a token to specific environments using AllowedEnvironments:
| Pattern | Access |
|---|---|
* |
All environments |
prod |
Single environment |
dev,test |
Named environments |
dev* |
All environments matching the prefix |
Endpoint-level restrictions
Individual endpoints enforce their own environment and visibility constraints:
{
"DatabaseObjectName": "SensitiveData",
"AllowedEnvironments": ["prod"],
"Hidden": true,
"AllowedMethods": ["GET"]
}Both token-level and endpoint-level restrictions must pass for a request to succeed. See Environments, access control for the full matrix.
Network security
IP restrictions
Configure allowed hosts and blocked IP ranges in environments/network-access-policy.json:
{
"allowedHosts": [
"localhost",
"127.0.0.1",
"your-internal-server.local"
],
"blockedIpRanges": [
"10.0.0.0/8",
"172.16.0.0/12",
"192.168.0.0/16"
]
}Security headers
Portway adds these headers to all responses automatically:
| Header | Value |
|---|---|
X-Content-Type-Options |
nosniff |
X-Frame-Options |
DENY |
Strict-Transport-Security |
max-age=31536000 |
Referrer-Policy |
strict-origin-when-cross-origin |
Content-Security-Policy |
default-src 'self'; object-src 'none'; frame-ancestors 'none'; ... |
Console pages at /ui add Cross-Origin-Opener-Policy and Cross-Origin-Resource-Policy, both same-origin. See Headers for the full set.
Secrets management
Automatic encryption
Portway encrypts plaintext secrets in settings.json files on next startup. Connection strings and authentication values written in plaintext become PWENC:... format.
Automatic encryption applies only to per-environment settings.json files and the MCP configuration store (mcp.db). It does not rewrite appsettings.json, so values placed there (such as WebUi:AdminApiKey) stay in plaintext.
Web UI accounts
Web UI accounts live in auth.db, with passwords hashed using PBKDF2-SHA256.
On the first start with no accounts, an existing WebUi:AdminApiKey becomes the account admin, with the key as its password. After that the setting is no longer read for sign-in and can be removed.
Never store a real admin key in appsettings.json. The shipped file intentionally contains the placeholder INSECURE-CHANGE-ME-admin-api-key, which Portway rejects in production: no account is seeded from it and an error is logged.
Supply the key through the environment instead:
Generate a strong key (32+ characters; shorter keys log a warning at startup):
With Azure Key Vault configured (KEYVAULT_URI), the key can also be served from the vault through the standard ASP.NET Core configuration pipeline. Environment variables and Key Vault values override anything in appsettings.json.
The Settings page in the Web UI shows the current key strength (not set / placeholder / weak / strong) under Security Posture.
Azure Key Vault
Store connection strings and server names in Azure Key Vault instead of settings.json:
Create secrets named by environment:
{environment}-ConnectionString{environment}-ServerName{environment}-Headers(JSON string)
Portway fetches these at startup and uses them identically to file-based configuration.
SQL Server permissions
When using Windows Authentication (NTLM) via IIS, configure the database account with minimum required permissions:
USE [master];
GO
IF NOT EXISTS (SELECT 1 FROM sys.server_principals WHERE name = N'DOMAIN\USER_NAME')
BEGIN
EXEC ('CREATE LOGIN [DOMAIN\USER_NAME] FROM WINDOWS;');
END
GO
USE [YourDatabase];
GO
IF NOT EXISTS (SELECT 1 FROM sys.database_principals WHERE name = N'DOMAIN\USER_NAME')
BEGIN
CREATE USER [DOMAIN\USER_NAME] FOR LOGIN [DOMAIN\USER_NAME];
END
GO
ALTER ROLE [db_datareader] ADD MEMBER [DOMAIN\USER_NAME]; -- Read tables/views
ALTER ROLE [db_datawriter] ADD MEMBER [DOMAIN\USER_NAME]; -- Write (insert/update/delete)
GRANT EXECUTE TO [DOMAIN\USER_NAME]; -- Stored procedures
GRANT VIEW DEFINITION TO [DOMAIN\USER_NAME]; -- Schema metadata
GOGrant only the roles your endpoints require. A read-only deployment needs only db_datareader.
Logging and auditing
Security events are logged at Warning or Debug level:
[DBG] Invalid token: {masked}
[WRN] IP {IP} has exceeded rate limit, blocking for {period}Enable request traffic logging to capture headers and bodies for security analysis:
{
"RequestTrafficLogging": {
"Enabled": true,
"CaptureHeaders": true,
"IncludeRequestBodies": true
}
}See Monitoring for traffic logging configuration details.
Recovering an account
Accounts are managed from the shell when nobody can sign in. Run these from the directory Portway runs in, so auth.db is found:
portway accounts list
portway accounts password <username> <new-password>
portway accounts create <username> <password> [administrator|viewer]promote, demote, enable, disable and delete are available too. Portway refuses any of them that would leave no active administrator.
Account roles
Accounts are either administrator or viewer.
An administrator can change anything the console exposes: settings, endpoints, environments, tokens, and other accounts. A viewer can read all of those pages, change its own password, and link or unlink its own single sign-on identity. Every other write returns 403, including creating accounts, so a viewer cannot promote itself.
Portway reads the role from the database on each write rather than from the session cookie. A demoted account loses write access on its next request, without waiting for its session to expire.
Accounts created before this behavior existed
Earlier builds stored the role but did not enforce it, so anything marked viewer still had full write access. After upgrading, open the Users page and check the accounts listed there.
Sessions are signed with portway.key, written next to auth.db on first use. Deleting that file signs everyone out.
Pre-deployment checklist
- HTTPS binding configured in IIS
- IIS Application Pool using minimum-privilege identity
- Web UI account created with a strong password, and
WebUi__AdminApiKeyremoved once it has been migrated -
ForwardedHeaders__KnownProxiesset to your reverse proxy, so per-IP rate limiting, the sign-in lockout, and the Web UI network gate see real client addresses - Account roles reviewed, so anyone who only needs to read the console holds
viewer -
portway.keykept with the deployment and excluded from backups that others can read - Azure Key Vault configured (if applicable)
- Initial token file removed from disk
- Tokens created with specific scopes and environments
- Rate limiting configured
- Firewall rules reviewed
- Security headers verified with a response inspection tool
Incident response: compromised token
- Open the Web UI and navigate to Access Tokens
- Click Rotate Token on the affected entry to invalidate it and generate a replacement
- Update all applications using the compromised token with the new value
- Enable traffic logging if not already active to monitor for continued unauthorized activity:
json
{ "RequestTrafficLogging": { "Enabled": true, "CaptureHeaders": true } } - Document the incident for your security audit trail
INFO
Manage all tokens in the Web UI under Tokens. The Tokens page lists all active (non-revoked, non-expired) tokens with their scope and environment restrictions.
WARNING
Token revocation is permanent. A revoked token cannot be reactivated. Create a new token for any affected user or system.
Portway