Ajeris , Access Controls Policy
Document Owner: Sarah Mitchell, Founder Contact: hi@ajeris.com Effective Date: April 15, 2026 Last Reviewed: April 15, 2026 Review Frequency: Annually, or upon significant infrastructure changes
1. Purpose
This policy defines how Ajeris controls access to production systems, consumer data, and administrative interfaces. It establishes the principle of least privilege, enforces multi-factor authentication on every infrastructure account, and specifies how user data is isolated from other users and from operators.
It applies to every person, service, and automated process that interacts with Ajeris infrastructure, code, or consumer data.
2. Scope
Covers:
- Administrative access to source code repositories, deployment platforms, and third-party service consoles
- Application-level access controls that isolate one user's data from another
- Authentication of inbound webhooks and API calls
- Authentication of end users
- Handling of third-party service credentials (OAuth tokens, API keys) on behalf of users
- Automated process-to-process authentication inside our services
3. Roles and responsibilities
| Role | Responsibility |
|---|---|
| Founder / Administrator | Owns all infrastructure accounts. Responsible for MFA enforcement, key rotation, and access reviews. |
| Application services (gateway, agent) | Enforce per-user data isolation at every query boundary. No service acts on behalf of a user without a valid, authenticated identity claim. |
| Per-user agent container | Runs with minimum required permissions. Cannot see other users' data, tokens, or memory. |
Ajeris currently operates as a solo founder + LLM-assisted engineering model. When additional personnel are onboarded, this section will be updated with named individuals and their scoped roles.
4. Identity model
4.1 User identity
Every user is identified by a stable UUID (users.id). The phone number is a mutable claim, not an identity. Changing phone numbers does not change the user's identity or cause data loss.
This pattern is documented in full at docs/identity-and-recovery.md.
4.2 First-time registration
- An unknown phone number sends an SMS to the Ajeris Twilio number.
- The gateway validates the webhook signature using Twilio's HMAC (
packages/gateway/src/routes/webhook.ts,validateTwilioRequest()). - The gateway mints a 192-bit cryptographically random token (
packages/gateway/src/onboarding/setup-token.ts:crypto.randomBytes(24).toString('hex')) and stores apending_registrationrow with a 24-hour TTL. - A setup link with the token is SMS'd back to the user.
- The user opens the link on their phone. Possession of the phone is the possession factor that proves the identity claim.
- The onboarding web app validates the token (exists, not consumed, not expired), the user completes setup, and the
usersrow is created atomically with the token marked consumed.
Tokens are single-use (consumed_at column). An attacker who observes a token after consumption cannot reuse it. Tokens expire in 24 hours regardless of consumption.
4.3 Current authentication posture
Consumer authentication today is SMS-based possession verification. The act of receiving a link on a phone number and tapping it proves ownership of that number. This is not phishing-resistant MFA per NIST SP 800-63B.
WebAuthn / passkey support is designed in docs/identity-and-recovery.md §6.3 and is on the roadmap. Until implemented, consumer authentication should be understood as single-factor possession.
5. Application-layer data isolation
5.1 Per-user scoping
Every database table that holds user data carries a userId foreign key. Every read and write scopes by userId. There is no application code path that reads across users.
5.2 Row-Level Security
PostgreSQL Row-Level Security is enforced through withUserContext() (packages/shared/src/db.ts). The helper sets a transaction-scoped session variable that RLS policies consume, so even a query bug cannot return another user's row.
5.3 Agent isolation
The per-user agent process runs with strict flags:
settingSources: [], the agent does not inherit parent environment configurationautoMemoryEnabled: false, the agent does not auto-persist memory across users
Each user's agent runs in its own Railway container. No shared state between containers except the central database (which is itself protected by RLS).
5.4 OAuth token isolation
Every OAuth access token (Google, Spotify, Hue, Uber, Slack, Plaid, and others) is stored with a unique constraint on (userId, service). Tokens are encrypted with pgcrypto pgp_sym_encrypt before storage (packages/shared/src/encryption.ts). Refresh flow re-encrypts on save. Tokens are never logged or returned in API responses.
6. Infrastructure access controls
6.1 Administrative accounts
Every account that can touch production is protected by multi-factor authentication:
| Provider | Use | MFA required |
|---|---|---|
| GitHub | Source code, CI, Dependabot | Yes |
| Railway | Production hosting, database, environment variables | Yes |
| Twilio | SMS gateway, phone numbers | Yes |
| Plaid | Financial data access | Yes |
| Anthropic | LLM inference | Yes |
| AWS (Alexa) | Alexa skill hosting | Yes |
MFA is enforced at the provider level. Account reviews are conducted annually or on personnel change.
6.2 Remote access
SSH key authentication only. Password authentication is disabled on every remote system. Keys are generated on a per-machine basis and revoked immediately when a machine is retired.
6.3 Production database
The production PostgreSQL database is hosted on Railway.
- Not publicly accessible. Connections restricted to Railway's internal network.
- SSL required on every connection.
- Application service accounts use unique credentials. Administrative access uses a separate credential with MFA on the Railway console.
- No shared database across users. RLS (see §5.2) protects data even from administrative console queries.
6.4 Secrets management
- Encryption keys, API keys, and database credentials live only in environment variables.
- Never committed to source.
.env,*.p8, and credentials files are.gitignored. - Railway environment variables are scoped per-service and not exposed to other services.
- Development and production use different encryption keys. No cross-environment key reuse.
7. Webhook and API authentication
7.1 Inbound webhooks
- Twilio: every inbound SMS webhook request is validated against Twilio's HMAC signature before any business logic runs. See
packages/gateway/src/routes/webhook.ts:66. - Alexa: every Alexa skill request is validated against the Alexa request signature before dispatch.
- OAuth callbacks: each OAuth provider uses its own signed redirect + state-parameter CSRF protection.
Unsigned requests are rejected with 401 before reaching application code.
7.2 Internal service-to-service
The agent container receives HTTP requests only from the gateway, authenticated via a shared secret (GATEWAY_INTERNAL_SECRET) set per-container at provisioning time. External traffic cannot reach the agent container directly.
8. Access provisioning and de-provisioning
8.1 Granting access
- New infrastructure accounts are created with the minimum permission set needed for the role.
- MFA is enforced before any action can be taken in the account.
- Keys / tokens are issued per-person; shared credentials are not permitted.
8.2 Revoking access
- Compromised credentials are revoked within 4 hours of discovery.
- When a person leaves the team, every account is revoked the same day and passwords on shared services are rotated.
- When a user deletes their account, all OAuth tokens for that user are immediately revoked at the provider (Plaid, Google, and others) and the encrypted token rows are cascade-deleted.
8.3 Access review
Access across all providers is reviewed:
- Annually at minimum
- Upon any personnel change
- Upon any security incident
The review confirms who has access, to what, and whether the access is still necessary. Stale access is removed during the review.
9. Audit and logging
- Gateway and agent services emit structured logs (Winston) for every authenticated action.
- Failed authentication attempts (bad Twilio signature, expired token, invalid setup token) are logged at
warnlevel with enough context to detect patterns. - Infrastructure console access (GitHub, Railway, Plaid, Twilio) is audited by the provider; logs are reviewed after any security incident.
10. Policy review
This policy is reviewed:
- Annually
- Upon any significant change to the identity, authentication, or isolation model
- Upon any security incident
- Before onboarding any new third-party data provider
Next scheduled review: April 2027.
11. Contact
Security concerns, access-control questions, and incident reports:
hi@ajeris.com , Sarah Mitchell, Founder Target initial response time: 4 hours during business hours.