auth-implementation
Implement authentication, authorization, tenant isolation, sessions, and protected routes. Use when adding sign-in, identity sync, provider integration, account linking, roles, or access control.
- Category
- auth
- Package
- auth-implementation/SKILL.md
- License
- MIT
- Author
- @tushaarmehtaa
- Tags
- authclerkauthjssupabaseauthorizationrlssessions
Install
Swipe for more runtimes.
Codex
Skills directory: ~/.codex/skills
Install globally
npx skills add tushaarmehtaa/tushar-skills --skill auth-implementation -g -a codex -yInvoke
$auth-implementation or /skillsYou can also describe the task naturally; runtimes may select the skill from its description.
Required access
Claude Code
Skills directory: ~/.claude/skills
Install globally
npx skills add tushaarmehtaa/tushar-skills --skill auth-implementation -g -a claude-code -yInvoke
/auth-implementationYou can also describe the task naturally; runtimes may select the skill from its description.
Required access
Cursor
Skills directory: ~/.cursor/skills
Install globally
npx skills add tushaarmehtaa/tushar-skills --skill auth-implementation -g -a cursor -yInvoke
/auth-implementationYou can also describe the task naturally; runtimes may select the skill from its description.
Required access
local coding agent required
This skill requires project files, terminal commands, and network access. Uploading it to a chat app does not provide equivalent execution.
ChatGPT Skills
This workflow needs a local coding environment or capabilities that a chat-only Skills upload does not provide.
Why local agent required →Instructions
Source: SKILL.mdAuthentication implementation
Implement identity and authorization end to end. Prefer the existing provider. Do not introduce or replace an identity system without an explicit user decision.
Workflow
- Detect framework/router version, auth package and version, database/ORM, session transport, user/account tables, tenant model, middleware or proxy, protected resources, and existing migrations.
- Distinguish authentication from authorization. Write an access matrix for public, signed-in, owner, team member, admin, and service/background paths that actually exist.
- Decide whether a local user mirror is necessary. If it is, model provider identities separately from application users when multiple login methods or providers are possible. Never link accounts from an unverified client-supplied email.
- Ask only when a material choice remains: provider selection, account-linking policy, deletion behavior, organization/tenant model, or whether existing users must be backfilled.
- Use the matching provider reference only after detecting the exact stack and installed version:
- Clerk for current Next.js Clerk protection and verified user synchronization.
- Auth.js for current Auth.js/NextAuth handlers, adapters, sessions, and route protection.
- Supabase Auth for public-profile synchronization and Supabase session handling.
- For Firebase, Auth0, custom JWT, or a provider/database combination not covered, preserve existing code and consult current primary provider documentation instead of adapting an incompatible example.
- Enforce access next to every protected read/mutation. Middleware/proxy may provide broad routing, but it is not the sole authorization boundary.
- For Supabase Data API access, implement RLS and grants with the actual token strategy. Add both
usingandwith checkwhere ownership may change. Service credentials stay server-only; do not create redundant service-role policies when the credential already bypasses RLS. - Make sync idempotent and verifiable. Prefer signed provider webhooks for lifecycle sync, or fetch authoritative provider data on the server for just-in-time sync. Handle create, update, deletion, replay, out-of-order delivery, and backfill.
Verification
Test new sign-up, returning login, logout, expiry/refresh, account switching, verified linking, provider update/deletion, and replayed sync. For every protected resource, run negative tests as unauthenticated, another user, another tenant, and a non-admin; test permitted owner/admin/service cases separately. Run migrations and the repository’s lint/type/test/build commands in the target runtime.
Output
Report provider/version and identity model, files/migrations changed, access matrix and enforcement points, sync strategy, RLS/grants, environment-variable names, automated verification evidence, and manual dashboard/backfill/production checks.
Bundled references
3 files · 238 lines
references/clerk.md
source ↗Clerk implementation
Read this reference only after detecting Clerk and its installed major version. The patterns target current Next.js App Router; use proxy.ts for Next.js 16+ and middleware.ts for Next.js 15 and earlier.
Contents
Protect resources
Use clerkMiddleware()/proxy for Clerk request integration, but authorize next to data access. Current Clerk guidance deprecates using createRouteMatcher() as the primary protection boundary.
// proxy.ts on Next.js 16+, middleware.ts on <=15
import { clerkMiddleware } from '@clerk/nextjs/server';
export default clerkMiddleware();
export const config = {
matcher: [
'/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
'/(api|trpc)(.*)',
],
};
import { auth } from '@clerk/nextjs/server';
export async function GET() {
const { userId, orgId } = await auth();
if (!userId) return Response.json({ error: 'Unauthorized' }, { status: 401 });
await requireResourceAccess({ userId, orgId, permission: 'project:read' });
// Read the authorized resource.
}
Use provider roles/permissions only where they match the product’s authorization model. Always include tenant/resource ownership checks.
Synchronize users
Avoid a local mirror if session claims/provider lookup are sufficient. When a mirror is required, prefer signed Clerk lifecycle webhooks for user.created, user.updated, and user.deleted.
import { verifyWebhook } from '@clerk/backend/webhooks';
export async function POST(request: Request) {
let event;
try {
event = await verifyWebhook(request);
} catch {
return new Response('Invalid signature', { status: 400 });
}
await processClerkEventIdempotently(event);
return new Response('OK');
}
Use the provider event ID as a unique idempotency key and upsert by Clerk user ID. Verify selected primary-email status from the signed/provider payload. Do not accept name/email/avatar from an authenticated browser and treat it as authoritative. Do not merge a local user by email unless the product has an explicit, verified account-linking flow that proves control of both identities.
Handle deletion/soft-deletion policy and backfill existing users. Return non-2xx for transient synchronous processing failures so Clerk can retry, or acknowledge only after a durable inbox/queue write.
Clerk with Supabase
Use the current native Clerk–Supabase third-party auth integration rather than the deprecated Supabase JWT template. Configure Clerk in Supabase’s third-party auth settings, then pass the Clerk session token through the Supabase client’s accessToken callback. RLS can read the Clerk subject with auth.jwt() ->> 'sub'.
const supabase = createClient(url, publishableKey, {
async accessToken() {
return (await auth()).getToken();
},
});
This token-scoped client respects RLS. Use a separate service client only for explicitly authorized administration.
Environment
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=
CLERK_SECRET_KEY=
CLERK_WEBHOOK_SIGNING_SECRET=
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=
Use names required by installed SDK versions. Keep secret and webhook keys server-only.
Verification
- Test signed, invalid, duplicate, out-of-order, update, and deletion webhooks.
- Test account switching and organization/tenant changes.
- Test every protected resource as anonymous, another user, another tenant, and allowed owner/admin.
- For Supabase, confirm two Clerk users cannot read or mutate each other’s rows through the Data API.
references/nextauth.md
source ↗Auth.js / NextAuth implementation
Read this reference only after detecting the installed Auth.js/NextAuth major version and router. The examples below follow current Auth.js v5-style Next.js setup; preserve a working v4 integration unless migration is requested.
Contents
- Configuration and handlers
- Session and authorization
- Adapters and account linking
- Environment
- Verification
Configuration and handlers
Keep configuration in auth.ts, then export route handlers separately.
// auth.ts
import NextAuth from 'next-auth';
import GitHub from 'next-auth/providers/github';
export const { auth, handlers, signIn, signOut } = NextAuth({
providers: [GitHub],
// Add an adapter/session strategy only after inspecting the existing schema.
});
// app/api/auth/[...nextauth]/route.ts
import { handlers } from '@/auth';
export const { GET, POST } = handlers;
Do not place the NextAuth() destructuring in route.ts and omit GET/POST; the route would not expose handlers.
Session and authorization
Use auth() on the server and enforce resource/tenant authorization next to access.
import { auth } from '@/auth';
export async function GET() {
const session = await auth();
if (!session?.user?.id) {
return Response.json({ error: 'Unauthorized' }, { status: 401 });
}
await requireProjectAccess(session.user.id);
}
Add TypeScript module augmentation when placing database IDs/roles on the session. Do not trust client session fields as the only authorization boundary. For Next.js 16+, follow current proxy.ts naming; preserve middleware.ts on older versions.
Adapters and account linking
Inspect the adapter’s required schema and existing migrations before adding it. Provider account records, verification tokens, sessions, and users have distinct lifecycle rules. Do not assume an adapter makes all account linking safe:
- allow automatic linking only under provider/documented guarantees;
- require verified email and explicit reauthentication when linking identities;
- preserve unique provider-account constraints;
- handle deleted/revoked accounts and database cleanup deliberately.
Callbacks must not assume a database user exists at a lifecycle point unless the installed adapter/version guarantees it. Test first-login and repeated-login behavior.
Environment
Current Auth.js commonly uses AUTH_SECRET and provider-specific AUTH_* variables; older NextAuth versions may use NEXTAUTH_SECRET/NEXTAUTH_URL. Detect the installed version and existing convention instead of adding both sets blindly.
Keep OAuth client secrets and auth secrets server-only. Add names, not values, to .env.example.
Verification
- Test provider callback/handler routes and CSRF/state behavior.
- Test new/returning login, logout, expiry/refresh, denied account, and account linking.
- Test database/session strategies if both are supported.
- Test anonymous, other-user, other-tenant, and non-admin access to protected resources.
- Run schema migrations plus lint/type/test/build.
references/supabase-auth.md
source ↗Supabase Auth implementation
Read this reference only when the project uses Supabase Auth. Decide whether an application profile table is needed; auth.users already owns authentication identities.
Contents
Profile synchronization
If app-specific fields require public.users/profiles, use a migration-backed trigger with a fixed search_path, idempotent conflict behavior, and only the metadata fields the application trusts.
create or replace function public.handle_new_auth_user()
returns trigger
language plpgsql
security definer
set search_path = ''
as $$
begin
insert into public.profiles (id, email, display_name, avatar_url)
values (
new.id,
new.email,
new.raw_user_meta_data ->> 'full_name',
new.raw_user_meta_data ->> 'avatar_url'
)
on conflict (id) do update
set email = excluded.email,
display_name = excluded.display_name,
avatar_url = excluded.avatar_url;
return new;
end;
$$;
drop trigger if exists on_auth_user_created on auth.users;
create trigger on_auth_user_created
after insert or update on auth.users
for each row execute function public.handle_new_auth_user();
Adapt table/field names to the existing schema. Decide how deletion, email changes, anonymous users, and metadata trust are handled. Restrict function execution/grants as appropriate and review all security definer code.
Sessions and authorization
Use current @supabase/ssr guidance for cookie-backed Next.js sessions: create clients per request, use getAll/setAll, await framework cookie APIs, and implement the required refresh proxy/middleware. Enforce access with RLS and server checks; a client auth hook is not authorization.
Prefer current publishable/secret key names when the project has migrated, while preserving supported legacy anon/service environment names until an intentional key migration.
Verification
- Create/update/delete users and confirm profile lifecycle behavior.
- Replay the trigger path and confirm no duplicate profile.
- Test session refresh/expiry in the target runtime.
- Test RLS as owner, another user, and anonymous for every profile-backed resource.
- Run the migration from a clean local database and regenerate types.