updated demo to use the new login redirect

This commit is contained in:
2026-06-11 20:59:02 +02:00
parent b6e9ddbb0e
commit 09c75c3f6b
8 changed files with 224 additions and 286 deletions

View File

@@ -57,7 +57,7 @@ A PHX frontend plugin is an Angular application packaged as a **custom element**
- Custom element tag: `frontend-plugin-demo`
- Sample routes: hello world, product view, address list
- GraphQL queries via PHX host Apollo (production) or a local Apollo client (development)
- Login flow for standalone development without a pre-configured API key
- PHX login redirect and callback route for standalone development without a pre-configured API key
- PrimeNG + Tailwind styling aligned with PHX
---
@@ -71,7 +71,7 @@ A PHX frontend plugin is an Angular application packaged as a **custom element**
For local standalone development you also need either:
- A PHX API user token in your development environment, or
- Valid credentials for the built-in login screen (see [Apollo, auth guard, and login](#apollo-auth-guard-and-login))
- Access to the PHX login page (see [Apollo, auth guard, and login](#apollo-auth-guard-and-login))
---
@@ -117,7 +117,7 @@ The manifest resolves to the compiled `main.js` in the `latest/` directory of th
### Standalone client (usual Angular workflow)
Runs the app with the **development** build configuration on port **4201** — routing, login, and a local Apollo client work without PHX.
Runs the app with the **development** build configuration on port **4201** — routing, PHX login redirect, and a local Apollo client work without embedding the plugin in PHX.
```bash
yarn client
@@ -175,7 +175,7 @@ phx-frontend-plugin-demo/
├── src/
│ ├── app/
│ │ ├── components/ # Demo pages (hello-world, product-view, …)
│ │ ├── login/ # Login form (standalone development)
│ │ ├── login.ts # Auth callback route (standalone development)
│ │ ├── services/
│ │ │ ├── apollo.service.ts
│ │ │ └── phoenix-host-bridge.service.ts
@@ -342,8 +342,8 @@ export const environment: Environment = {
production: false,
apiUrl: 'http://localhost:3000/admin-api',
wsUrl: 'ws://localhost:3000/admin-api',
apiKey: undefined, // or a PHX API user token; otherwise use the login route
serverUrl: 'https://localhost:4200',
apiKey: undefined, // or a PHX API user token; otherwise redirects to PHX login
serverUrl: 'https://localhost:4200', // PHX instance used for standalone login redirect
};
```
@@ -607,7 +607,7 @@ Use a custom port: `PORT=8080 yarn serve`.
In **production** (embedded in PHX), authentication is handled by the host. Use the Apollo client from `IPluginServices` via `PhoenixHostBridgeService` — you do not need a separate login flow.
In **development** (standalone), provide your own Apollo client and optional login.
In **development** (standalone), provide your own Apollo client and redirect unauthenticated users to the PHX login page. PHX redirects back to a local `/login` callback route that stores the token and returns the user to the original page.
#### Apollo provider
@@ -648,54 +648,53 @@ export class ApolloService {
Apply the same pattern for other host services (e.g. notifications) when you need standalone fallbacks.
#### Login component
#### Login callback route
For development without a preset API key, add a `/login` route that calls the PHX `login` mutation:
For development without a preset API key, add a `/login` route that acts as an **auth callback** — not a login form. When the user is unauthenticated, the auth guard sends them to the PHX login page (`environment.serverUrl`). After successful login, PHX redirects back to your plugin's `/login` route with an `authToken` query parameter and a base64-encoded `redirectTo` target.
```gql
mutation Login($username: String!, $password: String!) {
login(username: $username, password: $password) {
... on CurrentUser {
id
identifier
channels {
id
token
The callback component stores the token in `localStorage` and navigates back to the original page:
```ts
@Component({
selector: 'app-login',
template: `
<div class="flex flex-col items-center justify-center h-screen w-screen opacity-20">
<div class="animate-fadein duration-1000 animate-infinite animate-alternate text-4xl">Signing in...</div>
</div>
`,
})
export class Login {
constructor(private readonly route: ActivatedRoute) {
this.route.queryParams.subscribe((params) => {
const token = params['authToken'];
if (token) {
const redirectTo = decodeURIComponent(atob(params['redirectTo']));
localStorage.setItem('api-key', token);
window.history.replaceState({}, '', redirectTo);
window.location.href = redirectTo;
}
}
... on InvalidCredentialsError {
errorCode
message
}
... on NativeAuthStrategyError {
errorCode
message
}
... on EmailCodeAuthStrategyError {
errorCode
message
}
});
}
}
```
See `src/app/login/` in this repo for a complete form implementation.
See `src/app/login.ts` in this repo for the full implementation.
#### Auth guard
Redirect unauthenticated users to login in development only:
Redirect unauthenticated users to the PHX login page in development only. The `redirectTo` query parameter chains back through your plugin's `/login` callback:
```ts
@Injectable()
export class AuthGuard implements CanActivate {
private readonly router = inject(Router);
canActivate(_route: ActivatedRouteSnapshot, _state: RouterStateSnapshot): boolean {
const token = environment.apiKey ?? localStorage.getItem('api-key');
if (!environment.production && !token) {
this.router.navigate(['login'], {
queryParams: { redirectTo: btoa(window.location.pathname + window.location.search) },
});
const redirectTo = encodeURIComponent(
btoa(`${window.location.protocol}//${window.location.host}/login?redirectTo=${encodeURIComponent(btoa(window.location.href))}`)
);
window.location.href = `${environment.serverUrl}/login?redirectTo=${redirectTo}`;
return false;
}
return true;
}
@@ -748,7 +747,7 @@ This repository additionally runs `copy-latest.mjs` alongside `build` to publish
| Symptom | Things to check |
|---------|-----------------|
| PHX shows an old version of the plugin | Hard-refresh; confirm `serve.json` sets `Cache-Control: no-store` for JS; restart `yarn run plugin` |
| `401` / GraphQL auth errors in standalone mode | Set `apiKey` in `environment.development.ts` or log in via `/login` |
| `401` / GraphQL auth errors in standalone mode | Set `apiKey` in `environment.development.ts`, or ensure `serverUrl` points to your PHX instance so the login redirect works |
| `yarn add @phx-erp/shared` fails | Check network access to the public npm registry; retry `yarn install` |
| Routing broken inside PHX | Add route segments to `stripTrailingSegments` in `providePhoenixPluginWithPrimeNG` |
| Tailwind classes missing in a component | Add `@tailwind` directives to that component's `styles` |