updated demo to use the new login redirect
This commit is contained in:
77
README.md
77
README.md
@@ -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` |
|
||||
|
||||
Reference in New Issue
Block a user