App Integration
App Integration
How applications register with core.auth, authenticate users, and maintain their local user references.
App Registration
Every application that wants to use core.auth for identity must register as a client. Registration happens in core.auth's admin interface and produces credentials the app uses to participate in the auth flow.
core.auth SQL:
┌─────────────────────────────────────┐
│ registered_apps │
├─────────────────────────────────────┤
│ id (PK) │
│ name (human-readable) │
│ slug (unique, URL-safe) │
│ client_id (public identifier) │
│ client_secret (hashed, server-only) │
│ redirect_uris (JSON array) │
│ allowed_scopes (JSON array) │
│ webhook_url (invalidation callback) │
│ status (active/inactive/revoked) │
│ created_at │
│ updated_at │
└─────────────────────────────────────┘client_id vs client_secret
- client_id — public. Included in redirect URLs and auth requests. Not sensitive. Identifies the app to core.auth.
- client_secret — formerly used in server-to-server token exchanges. Superseded by the console project API key for all service calls under the relay model. Kept for legacy reference; server calls authenticate via
Authorization: Bearer <project_api_key>tocore.console.medkronos.com/v1/auth/*.
redirect_uris
A JSON array of allowed callback URLs. core.auth only redirects back to URLs in this list after authentication. This prevents open redirect attacks.
[
"https://todo-app.medkronos.com/auth/callback",
"https://todo-app.medkronos.com/auth/silent-refresh"
]allowed_scopes
What this app is permitted to request. An app can only ask for scopes listed here. An app with
["profile.read", "email.read"] cannot request password.change.User-App Access
When a user first authenticates through core.auth for a specific app, an access record is created:
core.auth SQL:
┌─────────────────────────────────────┐
│ user_app_access │
├─────────────────────────────────────┤
│ user_id (FK → users) │
│ app_id (FK → registered_apps) │
│ role (admin/user/viewer) │
│ granted_at │
│ granted_by (FK → users, nullable) │
│ PRIMARY KEY (user_id, app_id) │
└─────────────────────────────────────┘This record controls:
- Whether the user can access the app at all
- What role they have within the app (admin, user, viewer)
- Whether they need to be explicitly granted access or can self-serve
Access Models
| Model | How It Works | Use Case |
| Open | Any authenticated user can access | Internal tools, personal apps |
| Invitation | Admin must grant access | Restricted apps, team tools |
| Self-serve with approval | User requests, admin approves | Semi-open platforms |
The access model is configured per-app in
registered_apps.Linked Users (App-Side)
When a user authenticates and is redirected back to an app, the app creates a local linked user record. This is the app's only reference to the user.
App-side database (minimal):
app_db:
┌─────────────────────────────────────┐
│ linked_users │
├─────────────────────────────────────┤
│ id (local PK) │
│ core_auth_user_id (UUID, indexed) │
│ local_role (admin/user/viewer) │
│ local_preferences (JSON) │
│ linked_at │
│ last_seen_at │
└─────────────────────────────────────┘What Apps Store vs What They Don't
| ✅ App Stores | ❌ App Does NOT Store |
core_auth_user_id (reference) | Email address |
| Local role/permissions | Password hash |
| App-specific preferences | Display name |
| App-specific data (tasks, notes, etc.) | Phone number |
last_seen_at | 2FA configuration |
The app uses
core_auth_user_id to correlate its own data with the user. When it needs profile information, it calls core.auth's API — it doesn't cache identity data locally.Why Not Cache Profile Data?
- Stale data risk — user changes email in core.auth, app still shows old email
- Data minimization — app only stores what it needs for functionality
- Single deletion point — delete user in core.auth, all apps lose access. No orphaned profile copies.
- Simpler compliance — identity data lives in one system, not scattered across 10 apps
Data Flow Principle
core.auth owns: Apps own:
├── identity ├── their own data
├── credentials ├── local permissions
├── 2FA config ├── local preferences
├── sessions └── linked_users table
├── quotas
└── app registryApps are consumers of identity, never producers or storers of it.
Next: Session Architecture — rolling tokens, access/refresh lifecycle.