Mobile, push and DNN integration
Deliver respondent-friendly mobile experiences and integrate FormPlatform into an existing DNN portal without sacrificing its independent modern runtime.
Respondent External Authentication
Purpose
FormPlatform supports local respondent credentials plus Google and Facebook sign-in. Google uses OpenID Connect authorization-code flow with PKCE. Facebook uses the official ASP.NET Core Facebook OAuth handler because Facebook does not expose a general-purpose standards-compliant OIDC login endpoint.
Both providers end in the existing `Respondent` authentication cookie. The rest of the application therefore continues to use the same respondent authorization policy and client store.
Identity model
The management database contains `survey_external_identity`:
| Column | Purpose |
|---|---|
| `id` | FormPlatform-owned `varchar(36)` identity ID |
| `provider` | Normalized provider name (`google` or `facebook`) |
| `provider_subject` | Provider's stable subject identifier |
| `email` | Current provider email, if released |
| `display_name` | Name shown in the respondent UI |
| `picture_url` | Optional profile image URL |
| `created_at` | First sign-in time |
| `last_login_at` | Most recent sign-in time |
`(provider, provider_subject)` is unique. Email is informational and is never used to merge accounts. Provider access and refresh tokens are not stored.
For an authenticated external respondent, `survey_external_identity.id` is written to the deployment response table's `respondent_id`. The raw Google/Facebook subject is never written to a response. Public unauthenticated submissions keep `respondent_id = NULL`.
Existing anonymous response tables receive the nullable `respondent_id` column automatically when they are next opened or submitted. New anonymous response tables include it from creation.
Access rules
- Local respondents continue to see deployments assigned through their respondent lists.
- External respondents see active anonymous deployments only: `list_id IS NULL`, start time reached, and end time not passed.
- External respondents cannot use an external identity to enter a list-assigned deployment.
- Public users can still open and submit active anonymous deployments without signing in.
- When a repeatable anonymous deployment is opened by a signed-in Google/Facebook identity, the server loads that identity's latest response as the starting data. Submitting a previously completed response creates a new response; an `in_progress` response continues updating until completion. A public visitor without an identity still receives a blank form for each repeatable submission.
- For an anonymous deployment configured as a single-record deployment, the existing global one-record rule remains. Only the identity that owns that record (or the public `NULL` identity for a public answer) may reopen or update it.
- System administrators and Survey Assistants keep the existing assisted-entry routes and permissions.
Server routes
| Route | Function |
|---|---|
| `GET /api/respondent/external/providers` | Returns providers that are enabled and completely configured |
| `GET /api/respondent/external/google/login` | Starts Google OIDC login |
| `GET /api/respondent/external/facebook/login` | Starts Facebook login |
| `GET /api/respondent/external/callback` | Converts the temporary external principal into a FormPlatform respondent session |
| `GET /api/respondent/me` | Returns local/external identity kind and provider information |
`returnUrl` is accepted by the two login routes, but only application-local paths are allowed. Invalid or external URLs fall back to `/respondent/dashboard`.
Configuration
The current configuration shape is:
{
"RespondentExternalAuthentication": {
"Google": {
"Enabled": true,
"ClientId": "google-client-id",
"ClientSecret": "google-client-secret"
},
"Facebook": {
"Enabled": true,
"ClientId": "facebook-app-id",
"ClientSecret": "facebook-app-secret"
}
}
}
A provider is exposed to the login page only when `Enabled` is true and both credentials are non-empty.
Register these callback URLs in the provider consoles, replacing the origin with the deployed public HTTPS origin:
- Google: `https://your-host/signin-respondent-google`
- Facebook: `https://your-host/signin-respondent-facebook`
The checked-in `appsettings.json` contains disabled empty placeholders. Client secrets should not be committed. Moving the values to environment variables, .NET Secret Manager, or a production secret store is a separate configuration-hardening step.
Request flow
1. The login page calls `/api/respondent/external/providers` and displays only configured buttons.
2. The browser navigates to the provider login endpoint.
3. ASP.NET Core creates correlation/state protection and redirects to Google or Facebook.
4. The provider returns to its handler callback path.
5. The handler validates the provider response and creates a short-lived `Respondent.External` cookie.
6. `/api/respondent/external/callback` extracts the stable subject and upserts `survey_external_identity`.
7. FormPlatform discards the temporary cookie and signs the existing `Respondent` cookie with the internal ID.
8. The browser returns to a validated local URL, normally `/respondent/dashboard`.
Operational verification
With `DatabaseMigrations:Enabled=true`, start the application once so the Core migration creates the external identity table. Then verify:
1. Only configured provider buttons appear on `/respondent/login`.
2. Successful login redirects to `/respondent/dashboard`.
3. `/api/respondent/me` reports `identityKind: "external"` and the correct provider.
4. The dashboard lists only currently active deployments whose `list_id` is null.
5. A submitted anonymous response stores a 36-character internal ID in `respondent_id`.
6. That ID resolves to `survey_external_identity.id`; it is not the provider subject.
7. The same external session receives 403 for a list-assigned deployment.
---
Respondent mobile PWA and push notifications
The respondent application can be installed as a Progressive Web App (PWA). The mobile dashboard should use a cursor-paged ItemRenderer/repeater presentation rather than an administration DataGrid, so survey assignments remain readable on a narrow screen.
Push registration
Push notifications use the browser Push API, service worker, and VAPID keys. A respondent opens the dashboard over HTTPS, explicitly enables notifications, grants the browser permission, and the client posts its subscription to FormPlatform. The server stores the subscription against the local respondent or external identity and can send a title, body, and relative dashboard/deployment URL.
Push availability is controlled by the browser and device. Some mobile browsers require Google Play Services or system-level notification permission; an accepted browser permission does not guarantee the push service accepts registration. The UI must surface registration/send failures without breaking dashboard use.
Security and deployment
VAPID public/private keys are server secrets. Never place the private key in the Vue bundle, form schema, or public CMS content. HTTPS is mandatory for service workers and normal Push API use; localhost is the limited development exception. Use the public reverse-proxy origin consistently so service-worker scope, callback links, and authentication cookies resolve to the same site.
Chinese edition: RESPONDENT_MOBILE_PWA.zh-CN.md.
---
DNN portal bridge and SSO
FormPlatform remains an independent .NET application when integrated with DNN. The recommended topology is one public origin with two backend applications:
https://portal.example.com/ DNN
https://portal.example.com/formplatform/ FormPlatform behind IIS/Nginx reverse proxy
The DNN PortalBridge module supplies DNN navigation, entry permissions, diagnostics, a signed short-lived SSO ticket, and mapping from DNN users/roles to FormPlatform system users/roles. FormPlatform validates the ticket and maintains its own application cookie. Respondent accounts and external Google/Facebook respondent authentication remain separate from DNN system-user SSO.
Installation principles
Use the unified DNN setup package rather than compiling FormPlatform into DNN/.NET Framework. The setup publishes FormPlatform as a separate .NET service/application, installs the net48 DNN bridge ZIP, configures `/formplatform/` reverse proxying, writes protected secrets, and verifies DNN, FormPlatform, database, and SSO health.
The bridge and FormPlatform must share matching SSO issuer/audience/signing-secret configuration. The secret is protected at rest; never put it in the DNN module page settings or a public client script. Use the settings page to configure the FormPlatform public address, SSO enablement, and role mappings.
Reverse proxy
The proxy must preserve `Host` and `X-Forwarded-Proto`; FormPlatform must know the public `https` scheme and `/formplatform` path base when it generates redirects, asset URLs, payment callbacks, and license-origin checks. Kestrel should listen only on loopback when a reverse proxy terminates TLS.
Chinese edition: DNN_SSO.zh-CN.md.