Auth
This layer plugs Supabase sign-in into the admin shell of @plutocms/core. Core owns the /admin route, the sign-in page, the route guard, and the navbar. This layer registers an authDriver and a few other registry entries. See Admin shell.
The driver
| Field | Value |
|---|---|
user() | The Supabase user mapped from the JWT claims. The id is sub. The name is display_name, then full_name, then name, from user_metadata. |
loggedIn() | true when a Supabase session exists. The session cookie gives the same answer on the server and in the first client render, so there is no hydration mismatch. |
ready() | Resolves at once. The module plugin of @nuxtjs/supabase reads the session first. |
refresh() | Reads the session and the claims again. |
signOut() | Calls supabase.auth.signOut() and clears the session state. |
signIn | The email and password form AuthSignIn. It opens redirect, else /admin/home. |
guard(to) | The setup guard. |
links | Sign up and forgot password. |
publicPaths | See the next section. |
Public paths
| Path | A signed-in user |
|---|---|
/admin/signup | Goes to the admin home |
/admin/forgot-password | Goes to the admin home |
/admin/confirm | Stays on the page. A confirm link signs the user in. |
/admin/update-password | Stays on the page. A recovery link signs the user in. |
/admin/accept-invite | Stays on the page. An invite link signs the user in. |
/admin/setup | Stays on the page. The setup guard decides. |
The sign-up, forgot-password, update-password, and confirm pages use PlutoAdminAuthCard with the auth layout. Every auth page has the same frame as the sign-in page.
Accepting an invite
The page /admin/accept-invite is behind the invite email. The browser client uses PKCE. The default invite email gives tokens in the URL hash, which the PKCE client does not read. So the page reads the link itself.
| Link | What the page does |
|---|---|
?token_hash=...&type=invite | Verifies the one-time code as an invite |
?token_hash=...&type=magiclink (or signup) | Verifies the one-time code as a magic link |
#access_token=...&refresh_token=... | Sets the session from the tokens |
#error_code=otp_expired (or any error_code) | Shows "Link expired, ask for a new invite" |
| No token, but a session | Goes on to the password form |
| Nothing | Shows "Invalid link" |
The page clears the URL. Then it shows a password form with a confirm field. It updates the password, refreshes the driver, and goes to /admin/home.
The setup guard
The driver guard(to) runs on /admin/**, after ready() and before the sign-in rule. A new install goes to /admin/setup and not to the sign-in page.
- Setup not done, or the state cannot be read: every admin path but
/admin/setupgoes to/admin/setup. - Setup done:
/admin/setupgoes to/admin/login.
A finished setup is cached, so the guard does not fetch on every navigation. A result that is not "done" is read again each time. The guard never rejects.
Site info
site.name() is the website_title setting. site.url() is the website_url setting. In development, url() is empty, so View site opens /.
Banner
The migrations banner is in adminBanners. Core's admin layout renders it. It hides on /admin/migrations.
Permissions and language
This layer has no sync plugin. The core plugin pluto-auth-sync.client.ts watches loggedIn. It loads the capabilities and the stored language after sign-in, and clears the capabilities after sign-out.
useAuth()
useAuth() has login, requestPasswordReset, and updatePassword. Use usePlutoAuth() from core for the user and the sign-out.
The sign-up page posts to POST /api/_pluto/supabase/auth/signup. The body has username (3 characters or more), display_name, email, and password (6 characters or more). A failed sign-up is an HTTP error with the key supabase.errors.signupFailed. A 4xx status from Supabase Auth keeps its status. Any other status becomes 502.
Migrate an older app
Before version 0.11, this layer had its own navbar, its own pages/admin.vue, its own sign-in page, and its own auth middleware. They are gone.
- If you overrode
NavbarAdminorNavbarAdminProvider, delete the override. Add a link action tonavbarActions, an item toaccountMenu, or a banner toadminBanners. - If you overrode
pages/admin.vue, delete the override. Move extra work to a banner or a plugin. - If you overrode
pages/admin/(auth)/login.vue, delete it. Register anothersignIncomponent in anauthDriver. - If you used the
authroute middleware by name, remove the name. useAuth()no longer returnsisLoggedIn,user,logout, orallowedUnauthenticatedPaths. UseusePlutoAuth().- The
supabase.navbar.*keys are removed. Core haspluto.navbar.*. - The layer depends on
@plutocms/core. The package manager installs it with the layer. Do not add it to your app.
The old admin.vue showed a "not logged in" toast when the browser tab became visible with no session. Core's guard runs on navigation only, so this toast is gone.