This skill should be used when the user asks about "Clerk authentication", "JWT tokens", "Clerk session", "useAuth hook", "useSession hook", "getToken", "Clerk OAuth", "Clerk Organizations", "OIDC...
Clerk provides complete user authentication infrastructure including sign-up, sign-in, session management, and JWT tokens for integrating with external services like Alchemy. BlockDrive uses Clerk as the identity provider for the entire application.
Activate this skill when:
┌─────────────────────────────────────────────────────────────────┐
│ CLERK AUTH FLOW │
├─────────────────────────────────────────────────────────────────┤
│ 1. User visits app → Clerk UI component shown │
│ 2. User signs in (email, OAuth, etc.) │
│ 3. Clerk creates session → JWT available │
│ 4. App accesses user data via hooks │
│ 5. JWT used for external service auth (Alchemy, Supabase) │
└─────────────────────────────────────────────────────────────────┘
import {
useAuth, // Authentication state and methods
useUser, // User profile data
useSession, // Current session
useClerk // Clerk instance for advanced operations
} from '@clerk/clerk-react';
import { ClerkProvider } from '@clerk/clerk-react';
function App() {
return (
<ClerkProvider publishableKey={CLERK_PUBLISHABLE_KEY}>
<YourApp />
</ClerkProvider>
);
}
import { useAuth } from '@clerk/clerk-react';
function ProtectedComponent() {
const { isSignedIn, isLoaded } = useAuth();
if (!isLoaded) {
return <LoadingSpinner />;
}
if (!isSignedIn) {
return <RedirectToSignIn />;
}
return <ProtectedContent />;
}
Critical for Alchemy integration:
import { useAuth } from '@clerk/clerk-react';
function useAlchemyAuth() {
const { getToken } = useAuth();
const getAlchemyToken = async () => {
// Get the session token
const token = await getToken();
if (!token) {
throw new Error('No session token available');
}
return token;
};
return { getAlchemyToken };
}
import { useUser } from '@clerk/clerk-react';
function UserProfile() {
const { user, isLoaded } = useUser();
if (!isLoaded || !user) return null;
return (
<div>
<p>Email: {user.primaryEmailAddress?.emailAddress}</p>
<p>Name: {user.fullName}</p>
<p>ID: {user.id}</p>
</div>
);
}
import { useSession } from '@clerk/clerk-react';
function SessionInfo() {
const { session, isLoaded } = useSession();
if (!isLoaded || !session) return null;
return (
<div>
<p>Session ID: {session.id}</p>
<p>Last Active: {session.lastActiveAt}</p>
<p>Expires: {session.expireAt}</p>
</div>
);
}
// 1. Get Clerk session token
const { getToken } = useAuth();
const clerkToken = await getToken();
// 2. Use token with Alchemy Web Signer
const signerClient = new AlchemySignerWebClient({
connection: { jwt: clerkToken },
iframeConfig: { iframeContainerId: 'alchemy-signer-iframe-container' },
});
// 3. Authenticate with Alchemy
await signerClient.submitJwt({
jwt: clerkToken,
authProvider: 'clerk',
});
Clerk tokens expire. Handle refresh:
const { getToken } = useAuth();
// Always get fresh token before sensitive operations
const performSecureOperation = async () => {
const freshToken = await getToken(); // Gets fresh token if needed
// Use token...
};
For team/B2B features:
import { useOrganization, useOrganizationList } from '@clerk/clerk-react';
function TeamSelector() {
const { organization, isLoaded } = useOrganization();
const { organizationList, setActive } = useOrganizationList();
const switchOrg = async (orgId: string) => {
await setActive({ organization: orgId });
};
return (
<select onChange={(e) => switchOrg(e.target.value)}>
{organizationList?.map(org => (
<option key={org.organization.id} value={org.organization.id}>
{org.organization.name}
</option>
))}
</select>
);
}
import { useOrganization } from '@clerk/clerk-react';
function TeamMembers() {
const { organization, membershipList } = useOrganization({
membershipList: {},
});
return (
<ul>
{membershipList?.map(member => (
<li key={member.id}>
{member.publicUserData.firstName} - {member.role}
</li>
))}
</ul>
);
}
In Clerk Dashboard:
For Alchemy OIDC integration, Clerk acts as the OIDC provider:
// Clerk automatically provides OIDC-compliant JWTs
// The issuer URL is your Clerk frontend API URL
const CLERK_ISSUER_URL = 'https://your-app.clerk.accounts.dev/';
// Alchemy validates tokens against this issuer
import { useAuth, useSession, useUser } from '@clerk/clerk-react';
import { createContext, useContext, useEffect, useState } from 'react';
interface AuthContextType {
isAuthenticated: boolean;
userId: string | null;
getAuthToken: () => Promise<string>;
signOut: () => Promise<void>;
}
const AuthContext = createContext<AuthContextType | null>(null);
export function BlockDriveAuthProvider({ children }) {
const { isSignedIn, userId, getToken, signOut } = useAuth();
const { session } = useSession();
const getAuthToken = async () => {
const token = await getToken();
if (!token) throw new Error('Not authenticated');
return token;
};
return (
<AuthContext.Provider value={{
isAuthenticated: !!isSignedIn,
userId: userId || null,
getAuthToken,
signOut,
}}>
{children}
</AuthContext.Provider>
);
}
getToken() for fresh tokens// Sign out on sensitive errors
const handleSecurityError = async () => {
const { signOut } = useAuth();
await signOut();
// Redirect to sign-in
};
// Verify session is active before sensitive ops
const verifySession = async () => {
const { session } = useSession();
if (!session || session.status !== 'active') {
throw new Error('Invalid session');
}
};
For detailed patterns and configurations:
references/clerk-api.md - Complete Clerk API referencereferences/organizations.md - Organizations setup guidereferences/oauth-setup.md - OAuth provider configurationWorking implementations in examples/:
auth-provider.tsx - Complete auth providerprotected-route.tsx - Route protection patternisSignedIn === true)isLoaded === true)getToken({ skipCache: true })