diff --git a/docs-mintlify/guides/apps/analytics/overview.mdx b/docs-mintlify/guides/apps/analytics/overview.mdx index 40ab3dcc8..3cac35ac9 100644 --- a/docs-mintlify/guides/apps/analytics/overview.mdx +++ b/docs-mintlify/guides/apps/analytics/overview.mdx @@ -52,9 +52,9 @@ Session replay recording is disabled by default. Enable it when creating your cl ```ts import { HexclaveClientApp } from "@hexclave/next"; -export const stackClientApp = new HexclaveClientApp({ - projectId: process.env.NEXT_PUBLIC_STACK_PROJECT_ID!, - publishableClientKey: process.env.NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY!, +export const hexclaveClientApp = new HexclaveClientApp({ + projectId: process.env.NEXT_PUBLIC_HEXCLAVE_PROJECT_ID!, + publishableClientKey: process.env.NEXT_PUBLIC_HEXCLAVE_PUBLISHABLE_CLIENT_KEY!, tokenStore: "nextjs-cookie", analytics: { replays: { diff --git a/docs-mintlify/guides/apps/api-keys/overview.mdx b/docs-mintlify/guides/apps/api-keys/overview.mdx index 2536c6647..35d659768 100644 --- a/docs-mintlify/guides/apps/api-keys/overview.mdx +++ b/docs-mintlify/guides/apps/api-keys/overview.mdx @@ -51,10 +51,10 @@ User API keys are associated with individual users and allow them to authenticat ```typescript title="app/components/create-api-key.tsx" - import { stackServerApp } from "@/stack/server"; + import { hexclaveServerApp } from "@/hexclave/server"; export default async function CreateApiKey() { - const user = await stackServerApp.getUser({ or: 'redirect' }); + const user = await hexclaveServerApp.getUser({ or: 'redirect' }); const apiKey = await user.createApiKey({ description: "Admin-provisioned API key", @@ -93,16 +93,16 @@ User API keys are associated with individual users and allow them to authenticat def create_user_api_key(request): # Get the current user's access token from session/cookie - access_token = request.COOKIES.get('stack-access-token') + access_token = request.COOKIES.get('hexclave-access-token') # Create API key via client API response = requests.post( 'https://api.hexclave.com/api/v1/user-api-keys', headers={ - 'x-stack-access-type': 'client', - 'x-stack-project-id': stack_project_id, - 'x-stack-publishable-client-key': stack_publishable_client_key, - 'x-stack-access-token': access_token, + 'x-hexclave-access-type': 'client', + 'x-hexclave-project-id': hexclave_project_id, + 'x-hexclave-publishable-client-key': hexclave_publishable_client_key, + 'x-hexclave-access-token': access_token, }, json={ 'user_id': 'me', @@ -124,18 +124,18 @@ User API keys are associated with individual users and allow them to authenticat from fastapi import Cookie, HTTPException @app.post("/api/create-user-api-key") - async def create_user_api_key(stack_access_token: str = Cookie(None, alias="stack-access-token")): - if not stack_access_token: + async def create_user_api_key(hexclave_access_token: str = Cookie(None, alias="hexclave-access-token")): + if not hexclave_access_token: raise HTTPException(status_code=401, detail="Not authenticated") # Create API key via client API response = requests.post( 'https://api.hexclave.com/api/v1/user-api-keys', headers={ - 'x-stack-access-type': 'client', - 'x-stack-project-id': stack_project_id, - 'x-stack-publishable-client-key': stack_publishable_client_key, - 'x-stack-access-token': stack_access_token, + 'x-hexclave-access-type': 'client', + 'x-hexclave-project-id': hexclave_project_id, + 'x-hexclave-publishable-client-key': hexclave_publishable_client_key, + 'x-hexclave-access-token': hexclave_access_token, }, json={ 'user_id': 'me', @@ -158,7 +158,7 @@ User API keys are associated with individual users and allow them to authenticat @app.route('/api/create-user-api-key', methods=['POST']) def create_user_api_key(): - access_token = request.cookies.get('stack-access-token') + access_token = request.cookies.get('hexclave-access-token') if not access_token: return jsonify({'error': 'Not authenticated'}), 401 @@ -166,10 +166,10 @@ User API keys are associated with individual users and allow them to authenticat response = requests.post( 'https://api.hexclave.com/api/v1/user-api-keys', headers={ - 'x-stack-access-type': 'client', - 'x-stack-project-id': stack_project_id, - 'x-stack-publishable-client-key': stack_publishable_client_key, - 'x-stack-access-token': access_token, + 'x-hexclave-access-type': 'client', + 'x-hexclave-project-id': hexclave_project_id, + 'x-hexclave-publishable-client-key': hexclave_publishable_client_key, + 'x-hexclave-access-token': access_token, }, json={ 'user_id': 'me', @@ -217,10 +217,10 @@ Team API keys are associated with teams and can be used to provide access to tea ```typescript title="app/components/create-team-api-key.tsx" - import { stackServerApp } from "@/stack/server"; + import { hexclaveServerApp } from "@/hexclave/server"; export default async function CreateTeamApiKey({ teamId }: { teamId: string }) { - const team = await stackServerApp.getTeam(teamId); + const team = await hexclaveServerApp.getTeam(teamId); if (!team) { return
Team not found
; @@ -267,16 +267,16 @@ Team API keys are associated with teams and can be used to provide access to tea def create_team_api_key(request, team_id): # Get the current user's access token from session/cookie - access_token = request.COOKIES.get('stack-access-token') + access_token = request.COOKIES.get('hexclave-access-token') # Create team API key via client API response = requests.post( 'https://api.hexclave.com/api/v1/team-api-keys', headers={ - 'x-stack-access-type': 'client', - 'x-stack-project-id': stack_project_id, - 'x-stack-publishable-client-key': stack_publishable_client_key, - 'x-stack-access-token': access_token, + 'x-hexclave-access-type': 'client', + 'x-hexclave-project-id': hexclave_project_id, + 'x-hexclave-publishable-client-key': hexclave_publishable_client_key, + 'x-hexclave-access-token': access_token, }, json={ 'team_id': team_id, @@ -298,18 +298,18 @@ Team API keys are associated with teams and can be used to provide access to tea from fastapi import Cookie, HTTPException @app.post("/api/teams/{team_id}/api-keys") - async def create_team_api_key(team_id: str, stack_access_token: str = Cookie(None, alias="stack-access-token")): - if not stack_access_token: + async def create_team_api_key(team_id: str, hexclave_access_token: str = Cookie(None, alias="hexclave-access-token")): + if not hexclave_access_token: raise HTTPException(status_code=401, detail="Not authenticated") # Create team API key via client API response = requests.post( 'https://api.hexclave.com/api/v1/team-api-keys', headers={ - 'x-stack-access-type': 'client', - 'x-stack-project-id': stack_project_id, - 'x-stack-publishable-client-key': stack_publishable_client_key, - 'x-stack-access-token': stack_access_token, + 'x-hexclave-access-type': 'client', + 'x-hexclave-project-id': hexclave_project_id, + 'x-hexclave-publishable-client-key': hexclave_publishable_client_key, + 'x-hexclave-access-token': hexclave_access_token, }, json={ 'team_id': team_id, @@ -332,7 +332,7 @@ Team API keys are associated with teams and can be used to provide access to tea @app.route('/api/teams//api-keys', methods=['POST']) def create_team_api_key(team_id): - access_token = request.cookies.get('stack-access-token') + access_token = request.cookies.get('hexclave-access-token') if not access_token: return jsonify({'error': 'Not authenticated'}), 401 @@ -340,10 +340,10 @@ Team API keys are associated with teams and can be used to provide access to tea response = requests.post( 'https://api.hexclave.com/api/v1/team-api-keys', headers={ - 'x-stack-access-type': 'client', - 'x-stack-project-id': stack_project_id, - 'x-stack-publishable-client-key': stack_publishable_client_key, - 'x-stack-access-token': access_token, + 'x-hexclave-access-type': 'client', + 'x-hexclave-project-id': hexclave_project_id, + 'x-hexclave-publishable-client-key': hexclave_publishable_client_key, + 'x-hexclave-access-token': access_token, }, json={ 'team_id': team_id, @@ -487,10 +487,10 @@ When creating a key, pass `isPublic: true` to exempt it from Hexclave's secret s
```typescript title="app/components/create-api-key.tsx" - import { stackServerApp } from "@/stack/server"; + import { hexclaveServerApp } from "@/hexclave/server"; export default async function CreateApiKey() { - const user = await stackServerApp.getUser({ or: 'redirect' }); + const user = await hexclaveServerApp.getUser({ or: 'redirect' }); const apiKey = await user.createApiKey({ description: "Admin-provisioned API key", @@ -530,16 +530,16 @@ When creating a key, pass `isPublic: true` to exempt it from Hexclave's secret s def create_user_api_key(request): # Get the current user's access token from session/cookie - access_token = request.COOKIES.get('stack-access-token') + access_token = request.COOKIES.get('hexclave-access-token') # Create API key via client API response = requests.post( 'https://api.hexclave.com/api/v1/user-api-keys', headers={ - 'x-stack-access-type': 'client', - 'x-stack-project-id': stack_project_id, - 'x-stack-publishable-client-key': stack_publishable_client_key, - 'x-stack-access-token': access_token, + 'x-hexclave-access-type': 'client', + 'x-hexclave-project-id': hexclave_project_id, + 'x-hexclave-publishable-client-key': hexclave_publishable_client_key, + 'x-hexclave-access-token': access_token, }, json={ 'user_id': 'me', @@ -561,18 +561,18 @@ When creating a key, pass `isPublic: true` to exempt it from Hexclave's secret s from fastapi import Cookie, HTTPException @app.post("/api/create-user-api-key") - async def create_user_api_key(stack_access_token: str = Cookie(None, alias="stack-access-token")): - if not stack_access_token: + async def create_user_api_key(hexclave_access_token: str = Cookie(None, alias="hexclave-access-token")): + if not hexclave_access_token: raise HTTPException(status_code=401, detail="Not authenticated") # Create API key via client API response = requests.post( 'https://api.hexclave.com/api/v1/user-api-keys', headers={ - 'x-stack-access-type': 'client', - 'x-stack-project-id': stack_project_id, - 'x-stack-publishable-client-key': stack_publishable_client_key, - 'x-stack-access-token': stack_access_token, + 'x-hexclave-access-type': 'client', + 'x-hexclave-project-id': hexclave_project_id, + 'x-hexclave-publishable-client-key': hexclave_publishable_client_key, + 'x-hexclave-access-token': hexclave_access_token, }, json={ 'user_id': 'me', @@ -595,7 +595,7 @@ When creating a key, pass `isPublic: true` to exempt it from Hexclave's secret s @app.route('/api/create-user-api-key', methods=['POST']) def create_user_api_key(): - access_token = request.cookies.get('stack-access-token') + access_token = request.cookies.get('hexclave-access-token') if not access_token: return jsonify({'error': 'Not authenticated'}), 401 @@ -603,10 +603,10 @@ When creating a key, pass `isPublic: true` to exempt it from Hexclave's secret s response = requests.post( 'https://api.hexclave.com/api/v1/user-api-keys', headers={ - 'x-stack-access-type': 'client', - 'x-stack-project-id': stack_project_id, - 'x-stack-publishable-client-key': stack_publishable_client_key, - 'x-stack-access-token': access_token, + 'x-hexclave-access-type': 'client', + 'x-hexclave-project-id': hexclave_project_id, + 'x-hexclave-publishable-client-key': hexclave_publishable_client_key, + 'x-hexclave-access-token': access_token, }, json={ 'user_id': 'me', @@ -654,10 +654,10 @@ Requires the `$manage_api_keys` team permission. ```typescript title="app/components/create-team-api-key.tsx" - import { stackServerApp } from "@/stack/server"; + import { hexclaveServerApp } from "@/hexclave/server"; export default async function CreateTeamApiKey({ teamId }: { teamId: string }) { - const team = await stackServerApp.getTeam(teamId); + const team = await hexclaveServerApp.getTeam(teamId); if (!team) return
Team not found
; const teamApiKey = await team.createApiKey({ @@ -701,16 +701,16 @@ Requires the `$manage_api_keys` team permission. def create_team_api_key(request, team_id): # Get the current user's access token from session/cookie - access_token = request.COOKIES.get('stack-access-token') + access_token = request.COOKIES.get('hexclave-access-token') # Create team API key via client API response = requests.post( 'https://api.hexclave.com/api/v1/team-api-keys', headers={ - 'x-stack-access-type': 'client', - 'x-stack-project-id': stack_project_id, - 'x-stack-publishable-client-key': stack_publishable_client_key, - 'x-stack-access-token': access_token, + 'x-hexclave-access-type': 'client', + 'x-hexclave-project-id': hexclave_project_id, + 'x-hexclave-publishable-client-key': hexclave_publishable_client_key, + 'x-hexclave-access-token': access_token, }, json={ 'team_id': team_id, @@ -732,18 +732,18 @@ Requires the `$manage_api_keys` team permission. from fastapi import Cookie, HTTPException @app.post("/api/teams/{team_id}/api-keys") - async def create_team_api_key(team_id: str, stack_access_token: str = Cookie(None, alias="stack-access-token")): - if not stack_access_token: + async def create_team_api_key(team_id: str, hexclave_access_token: str = Cookie(None, alias="hexclave-access-token")): + if not hexclave_access_token: raise HTTPException(status_code=401, detail="Not authenticated") # Create team API key via client API response = requests.post( 'https://api.hexclave.com/api/v1/team-api-keys', headers={ - 'x-stack-access-type': 'client', - 'x-stack-project-id': stack_project_id, - 'x-stack-publishable-client-key': stack_publishable_client_key, - 'x-stack-access-token': stack_access_token, + 'x-hexclave-access-type': 'client', + 'x-hexclave-project-id': hexclave_project_id, + 'x-hexclave-publishable-client-key': hexclave_publishable_client_key, + 'x-hexclave-access-token': hexclave_access_token, }, json={ 'team_id': team_id, @@ -766,7 +766,7 @@ Requires the `$manage_api_keys` team permission. @app.route('/api/teams//api-keys', methods=['POST']) def create_team_api_key(team_id): - access_token = request.cookies.get('stack-access-token') + access_token = request.cookies.get('hexclave-access-token') if not access_token: return jsonify({'error': 'Not authenticated'}), 401 @@ -774,10 +774,10 @@ Requires the `$manage_api_keys` team permission. response = requests.post( 'https://api.hexclave.com/api/v1/team-api-keys', headers={ - 'x-stack-access-type': 'client', - 'x-stack-project-id': stack_project_id, - 'x-stack-publishable-client-key': stack_publishable_client_key, - 'x-stack-access-token': access_token, + 'x-hexclave-access-type': 'client', + 'x-hexclave-project-id': hexclave_project_id, + 'x-hexclave-publishable-client-key': hexclave_publishable_client_key, + 'x-hexclave-access-token': access_token, }, json={ 'team_id': team_id, @@ -823,10 +823,10 @@ Requires the `$manage_api_keys` team permission.
```typescript title="app/components/api-keys-list.tsx" - import { stackServerApp } from "@/stack/server"; + import { hexclaveServerApp } from "@/hexclave/server"; export default async function ApiKeysList() { - const user = await stackServerApp.getUser({ or: 'redirect' }); + const user = await hexclaveServerApp.getUser({ or: 'redirect' }); const apiKeys = await user.listApiKeys(); return ( @@ -875,16 +875,16 @@ Requires the `$manage_api_keys` team permission. def list_user_api_keys(request): # Get the current user's access token from session/cookie - access_token = request.COOKIES.get('stack-access-token') + access_token = request.COOKIES.get('hexclave-access-token') # List user's API keys via client API response = requests.get( 'https://api.hexclave.com/api/v1/user-api-keys?user_id=me', headers={ - 'x-stack-access-type': 'client', - 'x-stack-project-id': stack_project_id, - 'x-stack-publishable-client-key': stack_publishable_client_key, - 'x-stack-access-token': access_token, + 'x-hexclave-access-type': 'client', + 'x-hexclave-project-id': hexclave_project_id, + 'x-hexclave-publishable-client-key': hexclave_publishable_client_key, + 'x-hexclave-access-token': access_token, } ) @@ -900,18 +900,18 @@ Requires the `$manage_api_keys` team permission. from fastapi import Cookie, HTTPException @app.get("/api/user-api-keys") - async def list_user_api_keys(stack_access_token: str = Cookie(None, alias="stack-access-token")): - if not stack_access_token: + async def list_user_api_keys(hexclave_access_token: str = Cookie(None, alias="hexclave-access-token")): + if not hexclave_access_token: raise HTTPException(status_code=401, detail="Not authenticated") # List user's API keys via client API response = requests.get( 'https://api.hexclave.com/api/v1/user-api-keys?user_id=me', headers={ - 'x-stack-access-type': 'client', - 'x-stack-project-id': stack_project_id, - 'x-stack-publishable-client-key': stack_publishable_client_key, - 'x-stack-access-token': stack_access_token, + 'x-hexclave-access-type': 'client', + 'x-hexclave-project-id': hexclave_project_id, + 'x-hexclave-publishable-client-key': hexclave_publishable_client_key, + 'x-hexclave-access-token': hexclave_access_token, } ) @@ -928,7 +928,7 @@ Requires the `$manage_api_keys` team permission. @app.route('/api/user-api-keys', methods=['GET']) def list_user_api_keys(): - access_token = request.cookies.get('stack-access-token') + access_token = request.cookies.get('hexclave-access-token') if not access_token: return jsonify({'error': 'Not authenticated'}), 401 @@ -936,10 +936,10 @@ Requires the `$manage_api_keys` team permission. response = requests.get( 'https://api.hexclave.com/api/v1/user-api-keys?user_id=me', headers={ - 'x-stack-access-type': 'client', - 'x-stack-project-id': stack_project_id, - 'x-stack-publishable-client-key': stack_publishable_client_key, - 'x-stack-access-token': access_token, + 'x-hexclave-access-type': 'client', + 'x-hexclave-project-id': hexclave_project_id, + 'x-hexclave-publishable-client-key': hexclave_publishable_client_key, + 'x-hexclave-access-token': access_token, } ) @@ -955,12 +955,12 @@ The same pattern works for team API keys via `team.useApiKeys()` (client) or `te ### Validating an incoming API key on your server -This is the core authentication flow: an incoming request includes an API key, and your server needs to know **which user or team** it represents. Pass the plaintext key directly to `stackServerApp.getUser({ apiKey })` or `stackServerApp.getTeam({ apiKey })` — Hexclave validates it and returns the corresponding object, or `null` if the key is invalid, expired, or revoked. +This is the core authentication flow: an incoming request includes an API key, and your server needs to know **which user or team** it represents. Pass the plaintext key directly to `hexclaveServerApp.getUser({ apiKey })` or `hexclaveServerApp.getTeam({ apiKey })` — Hexclave validates it and returns the corresponding object, or `null` if the key is invalid, expired, or revoked. ```typescript title="app/api/protected/route.ts" - import { stackServerApp } from "@/stack/server"; + import { hexclaveServerApp } from "@/hexclave/server"; export async function GET(request: Request) { const auth = request.headers.get("authorization"); @@ -969,7 +969,7 @@ This is the core authentication flow: an incoming request includes an API key, a return new Response("Missing API key", { status: 401 }); } - const user = await stackServerApp.getUser({ apiKey }); + const user = await hexclaveServerApp.getUser({ apiKey }); if (!user) { return new Response("Invalid API key", { status: 401 }); } @@ -980,13 +980,13 @@ This is the core authentication flow: an incoming request includes an API key, a ```typescript title="app/api/team-protected/route.ts" - import { stackServerApp } from "@/stack/server"; + import { hexclaveServerApp } from "@/hexclave/server"; export async function GET(request: Request) { const apiKey = request.headers.get("authorization")?.replace(/^Bearer\s+/i, ""); if (!apiKey) return new Response("Missing API key", { status: 401 }); - const team = await stackServerApp.getTeam({ apiKey }); + const team = await hexclaveServerApp.getTeam({ apiKey }); if (!team) return new Response("Invalid team API key", { status: 401 }); return Response.json({ teamId: team.id, displayName: team.displayName }); @@ -1008,9 +1008,9 @@ This is the core authentication flow: an incoming request includes an API key, a check = requests.post( 'https://api.hexclave.com/api/v1/user-api-keys/check', headers={ - 'x-stack-access-type': 'server', - 'x-stack-project-id': stack_project_id, - 'x-stack-secret-server-key': stack_secret_server_key, + 'x-hexclave-access-type': 'server', + 'x-hexclave-project-id': hexclave_project_id, + 'x-hexclave-secret-server-key': hexclave_secret_server_key, }, json={'api_key': api_key}, ) @@ -1023,9 +1023,9 @@ This is the core authentication flow: an incoming request includes an API key, a user_resp = requests.get( f'https://api.hexclave.com/api/v1/users/{api_key_obj["user_id"]}', headers={ - 'x-stack-access-type': 'server', - 'x-stack-project-id': stack_project_id, - 'x-stack-secret-server-key': stack_secret_server_key, + 'x-hexclave-access-type': 'server', + 'x-hexclave-project-id': hexclave_project_id, + 'x-hexclave-secret-server-key': hexclave_secret_server_key, }, ) user = user_resp.json() @@ -1047,9 +1047,9 @@ This is the core authentication flow: an incoming request includes an API key, a check = requests.post( 'https://api.hexclave.com/api/v1/user-api-keys/check', headers={ - 'x-stack-access-type': 'server', - 'x-stack-project-id': stack_project_id, - 'x-stack-secret-server-key': stack_secret_server_key, + 'x-hexclave-access-type': 'server', + 'x-hexclave-project-id': hexclave_project_id, + 'x-hexclave-secret-server-key': hexclave_secret_server_key, }, json={'api_key': api_key}, ) @@ -1061,9 +1061,9 @@ This is the core authentication flow: an incoming request includes an API key, a user_resp = requests.get( f'https://api.hexclave.com/api/v1/users/{api_key_obj["user_id"]}', headers={ - 'x-stack-access-type': 'server', - 'x-stack-project-id': stack_project_id, - 'x-stack-secret-server-key': stack_secret_server_key, + 'x-hexclave-access-type': 'server', + 'x-hexclave-project-id': hexclave_project_id, + 'x-hexclave-secret-server-key': hexclave_secret_server_key, }, ) user = user_resp.json() @@ -1086,9 +1086,9 @@ This is the core authentication flow: an incoming request includes an API key, a check = requests.post( 'https://api.hexclave.com/api/v1/user-api-keys/check', headers={ - 'x-stack-access-type': 'server', - 'x-stack-project-id': stack_project_id, - 'x-stack-secret-server-key': stack_secret_server_key, + 'x-hexclave-access-type': 'server', + 'x-hexclave-project-id': hexclave_project_id, + 'x-hexclave-secret-server-key': hexclave_secret_server_key, }, json={'api_key': api_key}, ) @@ -1100,9 +1100,9 @@ This is the core authentication flow: an incoming request includes an API key, a user_resp = requests.get( f'https://api.hexclave.com/api/v1/users/{api_key_obj["user_id"]}', headers={ - 'x-stack-access-type': 'server', - 'x-stack-project-id': stack_project_id, - 'x-stack-secret-server-key': stack_secret_server_key, + 'x-hexclave-access-type': 'server', + 'x-hexclave-project-id': hexclave_project_id, + 'x-hexclave-secret-server-key': hexclave_secret_server_key, }, ) user = user_resp.json() @@ -1142,7 +1142,7 @@ When you already hold an `ApiKey` object (e.g. from `useApiKeys()`), use its syn ```typescript title="app/components/check-api-key.tsx" - import { stackServerApp } from "@/stack/server"; + import { hexclaveServerApp } from "@/hexclave/server"; export default async function CheckApiKeyValidity({ userId, @@ -1151,7 +1151,7 @@ When you already hold an `ApiKey` object (e.g. from `useApiKeys()`), use its syn userId: string, apiKeyId: string }) { - const user = await stackServerApp.getUser(userId); + const user = await hexclaveServerApp.getUser(userId); if (!user) return
User not found
; const apiKeys = await user.listApiKeys(); @@ -1202,16 +1202,16 @@ When you already hold an `ApiKey` object (e.g. from `useApiKeys()`), use its syn def check_api_key_validity(request, api_key_id): # Get the current user's access token from session/cookie - access_token = request.COOKIES.get('stack-access-token') + access_token = request.COOKIES.get('hexclave-access-token') # Get API key details via client API response = requests.get( f'https://api.hexclave.com/api/v1/user-api-keys/{api_key_id}', headers={ - 'x-stack-access-type': 'client', - 'x-stack-project-id': stack_project_id, - 'x-stack-publishable-client-key': stack_publishable_client_key, - 'x-stack-access-token': access_token, + 'x-hexclave-access-type': 'client', + 'x-hexclave-project-id': hexclave_project_id, + 'x-hexclave-publishable-client-key': hexclave_publishable_client_key, + 'x-hexclave-access-token': access_token, } ) @@ -1245,18 +1245,18 @@ When you already hold an `ApiKey` object (e.g. from `useApiKeys()`), use its syn from fastapi import Cookie, HTTPException @app.get("/api/check-api-key/{api_key_id}") - async def check_api_key_validity(api_key_id: str, stack_access_token: str = Cookie(None, alias="stack-access-token")): - if not stack_access_token: + async def check_api_key_validity(api_key_id: str, hexclave_access_token: str = Cookie(None, alias="hexclave-access-token")): + if not hexclave_access_token: raise HTTPException(status_code=401, detail="Not authenticated") # Get API key details via client API response = requests.get( f'https://api.hexclave.com/api/v1/user-api-keys/{api_key_id}', headers={ - 'x-stack-access-type': 'client', - 'x-stack-project-id': stack_project_id, - 'x-stack-publishable-client-key': stack_publishable_client_key, - 'x-stack-access-token': stack_access_token, + 'x-hexclave-access-type': 'client', + 'x-hexclave-project-id': hexclave_project_id, + 'x-hexclave-publishable-client-key': hexclave_publishable_client_key, + 'x-hexclave-access-token': hexclave_access_token, } ) @@ -1291,7 +1291,7 @@ When you already hold an `ApiKey` object (e.g. from `useApiKeys()`), use its syn @app.route('/api/check-api-key/', methods=['GET']) def check_api_key_validity(api_key_id): - access_token = request.cookies.get('stack-access-token') + access_token = request.cookies.get('hexclave-access-token') if not access_token: return jsonify({'error': 'Not authenticated'}), 401 @@ -1299,10 +1299,10 @@ When you already hold an `ApiKey` object (e.g. from `useApiKeys()`), use its syn response = requests.get( f'https://api.hexclave.com/api/v1/user-api-keys/{api_key_id}', headers={ - 'x-stack-access-type': 'client', - 'x-stack-project-id': stack_project_id, - 'x-stack-publishable-client-key': stack_publishable_client_key, - 'x-stack-access-token': access_token, + 'x-hexclave-access-type': 'client', + 'x-hexclave-project-id': hexclave_project_id, + 'x-hexclave-publishable-client-key': hexclave_publishable_client_key, + 'x-hexclave-access-token': access_token, } ) @@ -1360,10 +1360,10 @@ API keys can be revoked when they are no longer needed or if they have been comp
```typescript title="lib/api-keys.ts" - import { stackServerApp } from "@/stack/server"; + import { hexclaveServerApp } from "@/hexclave/server"; export async function revokeApiKey(userId: string, apiKeyId: string) { - const user = await stackServerApp.getUser(userId); + const user = await hexclaveServerApp.getUser(userId); if (!user) return; const apiKeys = await user.listApiKeys(); @@ -1404,16 +1404,16 @@ API keys can be revoked when they are no longer needed or if they have been comp def revoke_api_key(request, api_key_id): # Get the current user's access token from session/cookie - access_token = request.COOKIES.get('stack-access-token') + access_token = request.COOKIES.get('hexclave-access-token') # Revoke API key via client API (update with revoked: true) response = requests.patch( f'https://api.hexclave.com/api/v1/user-api-keys/{api_key_id}', headers={ - 'x-stack-access-type': 'client', - 'x-stack-project-id': stack_project_id, - 'x-stack-publishable-client-key': stack_publishable_client_key, - 'x-stack-access-token': access_token, + 'x-hexclave-access-type': 'client', + 'x-hexclave-project-id': hexclave_project_id, + 'x-hexclave-publishable-client-key': hexclave_publishable_client_key, + 'x-hexclave-access-token': access_token, }, json={ 'revoked': True, @@ -1432,18 +1432,18 @@ API keys can be revoked when they are no longer needed or if they have been comp from fastapi import Cookie, HTTPException @app.delete("/api/user-api-keys/{api_key_id}") - async def revoke_api_key(api_key_id: str, stack_access_token: str = Cookie(None, alias="stack-access-token")): - if not stack_access_token: + async def revoke_api_key(api_key_id: str, hexclave_access_token: str = Cookie(None, alias="hexclave-access-token")): + if not hexclave_access_token: raise HTTPException(status_code=401, detail="Not authenticated") # Revoke API key via client API (update with revoked: true) response = requests.patch( f'https://api.hexclave.com/api/v1/user-api-keys/{api_key_id}', headers={ - 'x-stack-access-type': 'client', - 'x-stack-project-id': stack_project_id, - 'x-stack-publishable-client-key': stack_publishable_client_key, - 'x-stack-access-token': stack_access_token, + 'x-hexclave-access-type': 'client', + 'x-hexclave-project-id': hexclave_project_id, + 'x-hexclave-publishable-client-key': hexclave_publishable_client_key, + 'x-hexclave-access-token': hexclave_access_token, }, json={ 'revoked': True, @@ -1463,7 +1463,7 @@ API keys can be revoked when they are no longer needed or if they have been comp @app.route('/api/user-api-keys/', methods=['DELETE']) def revoke_api_key(api_key_id): - access_token = request.cookies.get('stack-access-token') + access_token = request.cookies.get('hexclave-access-token') if not access_token: return jsonify({'error': 'Not authenticated'}), 401 @@ -1471,10 +1471,10 @@ API keys can be revoked when they are no longer needed or if they have been comp response = requests.patch( f'https://api.hexclave.com/api/v1/user-api-keys/{api_key_id}', headers={ - 'x-stack-access-type': 'client', - 'x-stack-project-id': stack_project_id, - 'x-stack-publishable-client-key': stack_publishable_client_key, - 'x-stack-access-token': access_token, + 'x-hexclave-access-type': 'client', + 'x-hexclave-project-id': hexclave_project_id, + 'x-hexclave-publishable-client-key': hexclave_publishable_client_key, + 'x-hexclave-access-token': access_token, }, json={ 'revoked': True, diff --git a/docs-mintlify/guides/apps/authentication/auth-providers.mdx b/docs-mintlify/guides/apps/authentication/auth-providers.mdx index a171748f2..ae402810c 100644 --- a/docs-mintlify/guides/apps/authentication/auth-providers.mdx +++ b/docs-mintlify/guides/apps/authentication/auth-providers.mdx @@ -8,7 +8,7 @@ Hexclave supports a variety of authentication providers to give your users flexi ## Overview -Authentication providers determine how users can sign in to your application. Stack supports the following provider types: +Authentication providers determine how users can sign in to your application. Hexclave supports the following provider types: - **Email/Password**: Traditional email and password authentication - **Magic Link**: Passwordless authentication via email links @@ -28,14 +28,14 @@ Authentication providers determine how users can sign in to your application. St Toggle the providers you want to enable for your application. - For OAuth providers, you can use Stack's shared keys for development or configure your own OAuth client ID and client secret for production. + For OAuth providers, you can use Hexclave's shared keys for development or configure your own OAuth client ID and client secret for production. ## Shared vs. Custom OAuth Keys - For development and testing, Stack provides shared OAuth keys that work out of the box. For production, you should set up your own OAuth client credentials. + For development and testing, Hexclave provides shared OAuth keys that work out of the box. For production, you should set up your own OAuth client credentials. ### Shared Keys diff --git a/docs-mintlify/guides/apps/authentication/auth-providers/github.mdx b/docs-mintlify/guides/apps/authentication/auth-providers/github.mdx index 35ae0bdad..2c8eb5626 100644 --- a/docs-mintlify/guides/apps/authentication/auth-providers/github.mdx +++ b/docs-mintlify/guides/apps/authentication/auth-providers/github.mdx @@ -6,7 +6,7 @@ description: "Set up GitHub as an authentication provider with Hexclave" This guide explains how to set up GitHub as an authentication provider with Hexclave. GitHub allows users to sign in to your Hexclave-enabled app using their GitHub account. - For Development purposes, Hexclave uses shared keys for this provider. Shared keys are automatically created by Stack, but show Stack's logo on the OAuth sign-in page. + For Development purposes, Hexclave uses shared keys for this provider. Shared keys are automatically created by Hexclave, but show Hexclave's logo on the OAuth sign-in page. You should replace these before you go into production. diff --git a/docs-mintlify/guides/apps/authentication/auth-providers/google.mdx b/docs-mintlify/guides/apps/authentication/auth-providers/google.mdx index 2e036b50b..0a5f19fe4 100644 --- a/docs-mintlify/guides/apps/authentication/auth-providers/google.mdx +++ b/docs-mintlify/guides/apps/authentication/auth-providers/google.mdx @@ -6,7 +6,7 @@ description: "Set up Google as an authentication provider with Hexclave" This guide explains how to set up Google as an authentication provider with Hexclave. Google OAuth2 allows users to sign in to your application using their Google account. - For Development purposes, Hexclave uses shared keys for this provider. Shared keys are automatically created by Stack, but show Stack's logo on the OAuth sign-in page. + For Development purposes, Hexclave uses shared keys for this provider. Shared keys are automatically created by Hexclave, but show Hexclave's logo on the OAuth sign-in page. You should replace these before you go into production. diff --git a/docs-mintlify/guides/apps/authentication/auth-providers/microsoft.mdx b/docs-mintlify/guides/apps/authentication/auth-providers/microsoft.mdx index 7faf09c11..893a93603 100644 --- a/docs-mintlify/guides/apps/authentication/auth-providers/microsoft.mdx +++ b/docs-mintlify/guides/apps/authentication/auth-providers/microsoft.mdx @@ -6,7 +6,7 @@ description: "Set up Microsoft as an authentication provider with Hexclave" This guide explains how to set up Microsoft as an authentication provider with Hexclave. Microsoft OAuth allows users to sign in to your application using their Microsoft account. - For Development purposes, Hexclave uses shared keys for this provider. Shared keys are automatically created by Stack, but show Stack's logo on the OAuth sign-in page. + For Development purposes, Hexclave uses shared keys for this provider. Shared keys are automatically created by Hexclave, but show Hexclave's logo on the OAuth sign-in page. You should replace these before you go into production. diff --git a/docs-mintlify/guides/apps/authentication/auth-providers/spotify.mdx b/docs-mintlify/guides/apps/authentication/auth-providers/spotify.mdx index b22051ab0..3006bf6e3 100644 --- a/docs-mintlify/guides/apps/authentication/auth-providers/spotify.mdx +++ b/docs-mintlify/guides/apps/authentication/auth-providers/spotify.mdx @@ -6,7 +6,7 @@ description: "Set up Spotify as an authentication provider with Hexclave" This guide explains how to set up Spotify as an authentication provider with Hexclave. Spotify OAuth allows users to sign in to your application using their Spotify account. - For Development purposes, Hexclave uses shared keys for this provider. Shared keys are automatically created by Stack, but show Stack's logo on the OAuth sign-in page. + For Development purposes, Hexclave uses shared keys for this provider. Shared keys are automatically created by Hexclave, but show Hexclave's logo on the OAuth sign-in page. You should replace these before you go into production. diff --git a/docs-mintlify/guides/apps/authentication/cli-authentication.mdx b/docs-mintlify/guides/apps/authentication/cli-authentication.mdx index 775a886fc..f94843370 100644 --- a/docs-mintlify/guides/apps/authentication/cli-authentication.mdx +++ b/docs-mintlify/guides/apps/authentication/cli-authentication.mdx @@ -7,7 +7,7 @@ sidebarTitle: CLI App Authentication If you're building your own command-line application, you can use Hexclave to let users log in from a terminal. - This page is about adding authentication to your own CLI app. For the official `stack` command, see the [Stack CLI guide](/guides/going-further/cli). + This page is about adding authentication to your own CLI app. For the official `hexclave` command, see the [Hexclave CLI guide](/guides/going-further/cli). To do so, we provide a Python template that you can use as a starting point. [Download it here](https://github.com/hexclave/hexclave/tree/main/docs/public/stack-auth-cli-template.py) and copy it into your project, for example: @@ -37,27 +37,27 @@ if refresh_token is None: # you can also store the refresh token in a file, and only prompt the user to log in if the file doesn't exist # you can now use the REST API with the refresh token -def stack_auth_request(method, endpoint, **kwargs): +def hexclave_auth_request(method, endpoint, **kwargs): # ... see the REST API overview for required Hexclave headers # https://docs.hexclave.com/api/overview def get_access_token(refresh_token): - access_token_response = stack_auth_request( + access_token_response = hexclave_auth_request( 'post', '/api/v1/auth/sessions/current/refresh', headers={ - 'x-stack-refresh-token': refresh_token, + 'x-hexclave-refresh-token': refresh_token, } ) return access_token_response['access_token'] def get_user_object(access_token): - return stack_auth_request( + return hexclave_auth_request( 'get', '/api/v1/users/me', headers={ - 'x-stack-access-token': access_token, + 'x-hexclave-access-token': access_token, } ) diff --git a/docs-mintlify/guides/apps/authentication/connected-accounts.mdx b/docs-mintlify/guides/apps/authentication/connected-accounts.mdx index d4a9915d7..3ff6b4147 100644 --- a/docs-mintlify/guides/apps/authentication/connected-accounts.mdx +++ b/docs-mintlify/guides/apps/authentication/connected-accounts.mdx @@ -3,14 +3,14 @@ title: "Connected Accounts" description: "Managing third-party OAuth access tokens" --- -Stack has good support for working with OAuth and OIDC providers, such as Google, Facebook, Microsoft, and others. +Hexclave has good support for working with OAuth and OIDC providers, such as Google, Facebook, Microsoft, and others. -Beyond using OAuth for signing in, Stack can manage your users' access token so you can invoke APIs on their behalf. For example, you can use this to send emails with Gmail, access repositories on GitHub, or access files on OneDrive. +Beyond using OAuth for signing in, Hexclave can manage your users' access token so you can invoke APIs on their behalf. For example, you can use this to send emails with Gmail, access repositories on GitHub, or access files on OneDrive. A connected account is simply an external account that is linked to the user in some way. If you are not using shared keys (see note below), any user created with "Sign up with OAuth" is automatically connected to the account they signed up with, but it's also possible to connect a user with a provider that is unavailable for sign in. - You cannot connect a user's accounts with shared OAuth keys. You need to set up your own OAuth client ID and client secret in Stack's dashboard. For more details, check [Going to Production](/guides/apps/launch-checklist/overview#oauth-providers). + You cannot connect a user's accounts with shared OAuth keys. You need to set up your own OAuth client ID and client secret in Hexclave's dashboard. For more details, check [Going to Production](/guides/apps/launch-checklist/overview#oauth-providers). ## Connecting with OAuth providers @@ -88,10 +88,12 @@ export default function Page() { To avoid showing the authorization page twice, you can already request scopes during the sign-in flow. This approach is optional. Some applications may prefer to request extra permissions only when needed, while others might want to obtain all necessary permissions upfront. -To do this, edit the `oauthScopesOnSignIn` setting of your `stackServerApp`: +To do this, edit the `oauthScopesOnSignIn` setting of your `hexclaveServerApp`: -```jsx title="stack/server.ts" -export const stackServerApp = new HexclaveServerApp({ +```jsx title="hexclave/server.ts" +import { HexclaveServerApp } from "@hexclave/next"; + +export const hexclaveServerApp = new HexclaveServerApp({ // ...your other settings... oauthScopesOnSignIn: { google: ['https://www.googleapis.com/auth/drive.readonly'] @@ -101,7 +103,7 @@ export const stackServerApp = new HexclaveServerApp({ ## OAuth account merging strategies -When a user attempts to sign in with an OAuth provider that matches an existing account, Stack provides different strategies for handling the authentication flow. +When a user attempts to sign in with an OAuth provider that matches an existing account, Hexclave provides different strategies for handling the authentication flow. The available strategies are: @@ -109,9 +111,9 @@ The available strategies are: - Link method (new default) - Block duplicates (most secure) -The "Link" strategy is the default behavior. If a user attempts to sign in with an OAuth provider that matches an existing account, Stack will link the OAuth identity to the existing account, and the user will be signed into that account. +The "Link" strategy is the default behavior. If a user attempts to sign in with an OAuth provider that matches an existing account, Hexclave will link the OAuth identity to the existing account, and the user will be signed into that account. This requires both of the credentials to be verified, or otherwise the link will be blocked, in the same way as the "Block" strategy. -The "Allow" strategy is the default behavior for old projects. If a user attempts to sign in with an OAuth provider that has an existing account with the same email address, Stack will create a separate account for the user. +The "Allow" strategy is the default behavior for old projects. If a user attempts to sign in with an OAuth provider that has an existing account with the same email address, Hexclave will create a separate account for the user. The "Block" strategy will explicitly raise an error if a user attempts to sign in with an OAuth provider that matches an existing account. diff --git a/docs-mintlify/guides/apps/authentication/fraud-protection.mdx b/docs-mintlify/guides/apps/authentication/fraud-protection.mdx index 83eb87f7d..938d3ec52 100644 --- a/docs-mintlify/guides/apps/authentication/fraud-protection.mdx +++ b/docs-mintlify/guides/apps/authentication/fraud-protection.mdx @@ -19,7 +19,7 @@ Every sign-up attempt is scored with the following fields. They're always availa | Field | Type | Operators | Description | |---|---|---|---| | `countryCode` | string (ISO-3166-1 alpha-2) | `equals`, `not_equals`, `in_list` | Geo-IP country of the request (e.g. `"US"`, `"DE"`, `"NG"`). Empty if it can't be resolved. | -| `riskScores.bot` | number (0-100) | `equals`, `not_equals`, `greater_than`, `greater_or_equal`, `less_than`, `less_or_equal` | Confidence that the sign-up is automated. Higher = more likely a bot. Stack Auth uses signals like the Cloudflare Turnstile verdict to compute this score. | +| `riskScores.bot` | number (0-100) | `equals`, `not_equals`, `greater_than`, `greater_or_equal`, `less_than`, `less_or_equal` | Confidence that the sign-up is automated. Higher = more likely a bot. Hexclave uses signals like the Cloudflare Turnstile verdict to compute this score. | | `riskScores.free_trial_abuse` | number (0-100) | same as `riskScores.bot` | Confidence that the user is attempting to abuse a free-trial / new-account incentive (multi-accounting, disposable infra, etc.). | The rule tester additionally exposes a **Turnstile** override (`ok` / `invalid` / `error`) so you can simulate how a given Turnstile verdict affects the resulting bot score. diff --git a/docs-mintlify/guides/apps/authentication/jwts.mdx b/docs-mintlify/guides/apps/authentication/jwts.mdx index 25ad735d1..d2f1c3897 100644 --- a/docs-mintlify/guides/apps/authentication/jwts.mdx +++ b/docs-mintlify/guides/apps/authentication/jwts.mdx @@ -140,10 +140,10 @@ export function UserProfile() { On the server side, you can access the JWT and its claims through the Hexclave API: ```typescript -import { stackServerApp } from '@/stack'; +import { hexclaveServerApp } from '@/hexclave/server'; export async function GET() { - const user = await stackServerApp.getUser(); + const user = await hexclaveServerApp.getUser(); if (!user) { return new Response('Unauthorized', { status: 401 }); @@ -225,7 +225,7 @@ const { payload } = await jose.jwtVerify(token, jwks, { ### Signing Keys -* Private keys are deterministically derived from your project ID, optional anonymous audience, and the `STACK_SERVER_SECRET` environment variable. This means no key material is ever stored in the database. +* Private keys are deterministically derived from your project ID, optional anonymous audience, and the `HEXCLAVE_SERVER_SECRET` environment variable. This means no key material is ever stored in the database. * The JWKS currently exposes both the latest key pair and a legacy compatibility key. Verification libraries automatically pick the correct key by matching the `kid` provided in the JWT header. * Tokens are always signed server-side; client SDKs never receive the private keys. @@ -239,7 +239,7 @@ const { payload } = await jose.jwtVerify(token, jwks, { ### Token Expiration -* JWTs have a limited lifetime (default is 10 minutes via `STACK_ACCESS_TOKEN_EXPIRATION_TIME`) +* JWTs have a limited lifetime (default is 10 minutes via `HEXCLAVE_ACCESS_TOKEN_EXPIRATION_TIME`) * Hexclave automatically refreshes tokens before they expire * Always check the `exp` claim when manually handling JWTs diff --git a/docs-mintlify/guides/apps/authentication/restricted-users.mdx b/docs-mintlify/guides/apps/authentication/restricted-users.mdx index 0ccc11ae4..a5ba843e7 100644 --- a/docs-mintlify/guides/apps/authentication/restricted-users.mdx +++ b/docs-mintlify/guides/apps/authentication/restricted-users.mdx @@ -4,9 +4,9 @@ description: "Understand and handle users with limited access" sidebarTitle: "Restricted Users" --- -Restricted users are signed-in users whose account exists, but has not been granted normal application access yet. Stack marks these users with `user.isRestricted === true` and provides a `user.restrictedReason` explaining why. +Restricted users are signed-in users whose account exists, but has not been granted normal application access yet. Hexclave marks these users with `user.isRestricted === true` and provides a `user.restrictedReason` explaining why. -By default, Stack Auth treats restricted users like unauthenticated users in most SDK calls. This prevents accounts that still need verification, review, or conversion from accidentally getting access to protected product flows. +By default, Hexclave treats restricted users like unauthenticated users in most SDK calls. This prevents accounts that still need verification, review, or conversion from accidentally getting access to protected product flows. ## When users are restricted @@ -19,9 +19,9 @@ Users can be restricted for a few reasons: You can inspect the reason from the SDK: ```ts my-app.ts -import { stackServerApp } from "../src/stack/server"; +import { hexclaveServerApp } from "../src/hexclave/server"; -const user = await stackServerApp.getUser({ includeRestricted: true }); +const user = await hexclaveServerApp.getUser({ includeRestricted: true }); if (user?.isRestricted) { console.log(user.restrictedReason?.type); @@ -42,9 +42,9 @@ Most calls exclude restricted users unless you explicitly opt in. Use `includeRe ```ts my-app.ts -import { stackServerApp } from "../src/stack/server"; +import { hexclaveServerApp } from "../src/hexclave/server"; -const user = await stackServerApp.getUser({ includeRestricted: true }); +const user = await hexclaveServerApp.getUser({ includeRestricted: true }); if (user?.isRestricted) { console.log("Needs onboarding:", user.restrictedReason?.type); @@ -53,10 +53,10 @@ if (user?.isRestricted) { ```tsx my-react-component.tsx "use client"; -import { stackClientApp } from "../src/stack/client"; +import { hexclaveClientApp } from "../src/hexclave/client"; export default function OnboardingGate() { - const user = stackClientApp.useUser({ includeRestricted: true }); + const user = hexclaveClientApp.useUser({ includeRestricted: true }); if (!user) { return Sign in; @@ -97,9 +97,9 @@ For API routes or backend actions, keep using the default behavior unless the en ## Restricted users in JWTs -Restricted users receive tokens with `is_restricted` and `restricted_reason` claims. If your backend verifies Stack Auth JWTs directly, make sure you reject restricted users unless the endpoint intentionally supports them. +Restricted users receive tokens with `is_restricted` and `restricted_reason` claims. If your backend verifies Hexclave JWTs directly, make sure you reject restricted users unless the endpoint intentionally supports them. -When fetching Stack Auth's JWKS, restricted-user signing keys are excluded by default. Include them only for services that intentionally accept restricted users: +When fetching Hexclave's JWKS, restricted-user signing keys are excluded by default. Include them only for services that intentionally accept restricted users: ```txt jwks-url.txt /.well-known/jwks.json?include_restricted=true diff --git a/docs-mintlify/guides/apps/authentication/sign-up-rules.mdx b/docs-mintlify/guides/apps/authentication/sign-up-rules.mdx index ac212cca4..6a38d78f6 100644 --- a/docs-mintlify/guides/apps/authentication/sign-up-rules.mdx +++ b/docs-mintlify/guides/apps/authentication/sign-up-rules.mdx @@ -5,7 +5,7 @@ description: "Control who can sign up for your application with customizable rul Sign-up rules let you control who can sign up for your application. You can create rules that evaluate sign-up attempts based on conditions like email domain or authentication method, then allow, reject, or restrict users accordingly. -Rules are evaluated during sign-up for all authentication methods (password, magic link, OAuth, passkey). When a user attempts to sign up, Stack evaluates each rule in priority order—the first matching rule determines the outcome. If no rules match, the default action is used. +Rules are evaluated during sign-up for all authentication methods (password, magic link, OAuth, passkey). When a user attempts to sign up, Hexclave evaluates each rule in priority order—the first matching rule determines the outcome. If no rules match, the default action is used. ## Creating rules diff --git a/docs-mintlify/guides/apps/authentication/user-onboarding.mdx b/docs-mintlify/guides/apps/authentication/user-onboarding.mdx index deab9042f..d4fa3bd57 100644 --- a/docs-mintlify/guides/apps/authentication/user-onboarding.mdx +++ b/docs-mintlify/guides/apps/authentication/user-onboarding.mdx @@ -74,11 +74,11 @@ Next, we can create a hook/function to check if the user has completed onboardin ```jsx - import { stackServerApp } from '@/stack/server'; + import { hexclaveServerApp } from '@/hexclave/server'; import { redirect } from 'next/navigation'; export async function ensureOnboarded() { - const user = await stackServerApp.getUser(); + const user = await hexclaveServerApp.getUser(); if (!user.clientReadOnlyMetadata.onboarded) { redirect('/onboarding'); } @@ -108,11 +108,11 @@ You can then use these functions wherever onboarding is required: ```jsx import { ensureOnboarding } from '@/app/onboarding-functions'; - import { stackServerApp } from '@/stack/server'; + import { hexclaveServerApp } from '@/hexclave/server'; export default async function HomePage() { await ensureOnboarding(); - const user = await stackServerApp.getUser(); + const user = await hexclaveServerApp.getUser(); return (
Welcome to the app, {user.displayName}
diff --git a/docs-mintlify/guides/apps/data-vault/overview.mdx b/docs-mintlify/guides/apps/data-vault/overview.mdx index 4e22df8ef..c4b1ddcfd 100644 --- a/docs-mintlify/guides/apps/data-vault/overview.mdx +++ b/docs-mintlify/guides/apps/data-vault/overview.mdx @@ -58,7 +58,7 @@ Click any store in the **Stores** list to open its detail page. From there you c Your secret can be any string, but for strong security it should be at least 32 characters long and provide 256 bits of entropy. Store it as an environment variable: ```bash title=".env" -STACK_DATA_VAULT_SECRET=your-randomly-generated-secret-here +HEXCLAVE_DATA_VAULT_SECRET=your-randomly-generated-secret-here ``` ### 3. Use the SDK @@ -66,18 +66,20 @@ STACK_DATA_VAULT_SECRET=your-randomly-generated-secret-here Data Vault is accessed through the **server app** only — it requires your secret server key. ```typescript title="server-example.ts" -const store = await stackServerApp.getDataVaultStore("my-store-id"); +import { hexclaveServerApp } from "@/hexclave/server"; + +const store = await hexclaveServerApp.getDataVaultStore("my-store-id"); const key = user.id; // Store a value await store.setValue(key, "my-sensitive-value", { - secret: process.env.STACK_DATA_VAULT_SECRET, + secret: process.env.HEXCLAVE_DATA_VAULT_SECRET, }); // Retrieve a value const value = await store.getValue(key, { - secret: process.env.STACK_DATA_VAULT_SECRET, + secret: process.env.HEXCLAVE_DATA_VAULT_SECRET, }); // value is the decrypted string, or null if the key doesn't exist ``` @@ -89,7 +91,7 @@ const value = await store.getValue(key, { Returns a `DataVaultStore` object for the given store ID. The store must already exist in your project config (created via the dashboard). ```typescript -const store = await stackServerApp.getDataVaultStore("my-store-id"); +const store = await hexclaveServerApp.getDataVaultStore("my-store-id"); ``` ### `store.getValue(key, { secret })` @@ -98,7 +100,7 @@ Retrieves the decrypted value for the given key, or `null` if the key doesn't ex ```typescript const value = await store.getValue("some-key", { - secret: process.env.STACK_DATA_VAULT_SECRET, + secret: process.env.HEXCLAVE_DATA_VAULT_SECRET, }); ``` @@ -108,7 +110,7 @@ Stores an encrypted value for the given key. If the key already exists, it is ov ```typescript await store.setValue("some-key", "some-value", { - secret: process.env.STACK_DATA_VAULT_SECRET, + secret: process.env.HEXCLAVE_DATA_VAULT_SECRET, }); ``` diff --git a/docs-mintlify/guides/apps/emails/overview.mdx b/docs-mintlify/guides/apps/emails/overview.mdx index 3db2cc778..abb05a81f 100644 --- a/docs-mintlify/guides/apps/emails/overview.mdx +++ b/docs-mintlify/guides/apps/emails/overview.mdx @@ -36,7 +36,7 @@ There are two categories of email: When sending, specify the category: ```typescript -await stackServerApp.sendEmail({ +await hexclaveServerApp.sendEmail({ userIds: ['user-id'], html: '

Check out our new feature!

', subject: 'Product Updates', @@ -48,12 +48,12 @@ If a user has unsubscribed from Marketing emails, the email will be automaticall ## Sending emails -Emails are sent from your server using `stackServerApp.sendEmail()`. You must provide the content (HTML, a template, or a draft) and the recipients. +Emails are sent from your server using `hexclaveServerApp.sendEmail()`. You must provide the content (HTML, a template, or a draft) and the recipients. ### Send to specific users ```typescript -await stackServerApp.sendEmail({ +await hexclaveServerApp.sendEmail({ userIds: ['user-id-1', 'user-id-2'], subject: 'Welcome to our platform!', html: '

Welcome!

Thanks for joining us.

', @@ -63,7 +63,7 @@ await stackServerApp.sendEmail({ ### Send to all users ```typescript -await stackServerApp.sendEmail({ +await hexclaveServerApp.sendEmail({ allUsers: true, templateId: 'your-template-id', subject: 'We just shipped a big update', @@ -78,7 +78,7 @@ await stackServerApp.sendEmail({ If you've composed an email in the dashboard's draft editor, you can trigger it programmatically. See [Drafts](/guides/dashboard-references/emails/drafts) for the full workflow. ```typescript -await stackServerApp.sendEmail({ +await hexclaveServerApp.sendEmail({ userIds: ['user-id'], draftId: 'your-draft-id', }); @@ -87,7 +87,7 @@ await stackServerApp.sendEmail({ ### Full options ```typescript -await stackServerApp.sendEmail({ +await hexclaveServerApp.sendEmail({ // Recipients - exactly one of these is required: userIds: ['user-id-1'], // specific users // allUsers: true, // or all users in your project @@ -136,11 +136,11 @@ type SendEmailOptions = { `sendEmail` resolves once the email has been queued. If validation fails, the user IDs do not exist, or the project is still using the shared email server, it throws a Hexclave known error with a stable `errorCode`: ```typescript -import { stackServerApp } from '@/stack/server'; +import { hexclaveServerApp } from '@/hexclave/server'; export async function sendTestEmail(userId: string) { try { - await stackServerApp.sendEmail({ + await hexclaveServerApp.sendEmail({ userIds: [userId], html: '

Hello!

', subject: 'Test Email', @@ -180,7 +180,7 @@ Common errors are: Pass a `scheduledAt` date to delay delivery. The email enters the pipeline immediately but won't be sent until the scheduled time. ```typescript -await stackServerApp.sendEmail({ +await hexclaveServerApp.sendEmail({ userIds: ['user-id'], html: '

Happy New Year!

', subject: 'Happy New Year!', @@ -197,10 +197,10 @@ Emails integrate with Hexclave UI components automatically (for example verifica For custom flows, trigger `sendEmail` from your server code: ```typescript -import { stackServerApp } from '@hexclave/next'; +import { hexclaveServerApp } from '@/hexclave/server'; export async function inviteUser(userId: string) { - const result = await stackServerApp.sendEmail({ + const result = await hexclaveServerApp.sendEmail({ userIds: [userId], templateId: 'invitation-template', subject: "You're invited!", diff --git a/docs-mintlify/guides/apps/launch-checklist/overview.mdx b/docs-mintlify/guides/apps/launch-checklist/overview.mdx index 5e46320f3..c7e19033c 100644 --- a/docs-mintlify/guides/apps/launch-checklist/overview.mdx +++ b/docs-mintlify/guides/apps/launch-checklist/overview.mdx @@ -1,20 +1,20 @@ --- title: "Launch Checklist" -description: "Steps to prepare Stack for production use" +description: "Steps to prepare Hexclave for production use" icon: "/images/app-icons/launch-checklist.svg" --- -Stack makes development easy with various default settings, but these settings need to be optimized for security and user experience when moving to production. Here's a checklist of things you need to do before switching to production mode: +Hexclave makes development easy with various default settings, but these settings need to be optimized for security and user experience when moving to production. Here's a checklist of things you need to do before switching to production mode: ## Domains -By default, Stack allows all localhost paths as valid callback URLs. This is convenient for development but poses a security risk in production because attackers could use their own domains as callback URLs to intercept sensitive information. Therefore, in production, Stack must know your domain (e.g., `https://your-website.com`) and only allow callbacks from those domains. +By default, Hexclave allows all localhost paths as valid callback URLs. This is convenient for development but poses a security risk in production because attackers could use their own domains as callback URLs to intercept sensitive information. Therefore, in production, Hexclave must know your domain (e.g., `https://your-website.com`) and only allow callbacks from those domains. Follow these steps when you're ready to push your application to production: - Navigate to the `Domain & Handlers` tab in the Stack dashboard. If you haven't configured your handler, you can leave it as the default. (Learn more about handlers [here](/sdk/objects/stack-app)). + Navigate to the `Domain & Handlers` tab in the Hexclave dashboard. If you haven't configured your handler, you can leave it as the default. (Learn more about handlers [here](/sdk/objects/stack-app)). For enhanced security, disable the `Allow all localhost callbacks for development` option. @@ -23,13 +23,13 @@ Follow these steps when you're ready to push your application to production: ## OAuth providers -Stack uses shared OAuth keys for development to simplify setup when using "Sign in with Google/GitHub/etc." However, this isn't secure for production as it displays "Stack Development" on the providers' consent screens, making it unclear to users if the OAuth request is genuinely from your site. Thus, you should configure your own OAuth keys with the providers and connect them to Stack. +Hexclave uses shared OAuth keys for development to simplify setup when using "Sign in with Google/GitHub/etc." However, this isn't secure for production as it displays "Hexclave Development" on the providers' consent screens, making it unclear to users if the OAuth request is genuinely from your site. Thus, you should configure your own OAuth keys with the providers and connect them to Hexclave. To use your own OAuth provider setups in production, follow these steps for each provider you use: - On the provider's website, create an OAuth app and set the callback URL to the corresponding Stack callback URL. Copy the client ID and client secret. + On the provider's website, create an OAuth app and set the callback URL to the corresponding Hexclave callback URL. Copy the client ID and client secret. @@ -116,19 +116,19 @@ To use your own OAuth provider setups in production, follow these steps for each - Go to the `Auth Methods` section in the Stack dashboard, open the provider's settings, switch from shared keys to custom keys, and enter the client ID and client secret. + Go to the `Auth Methods` section in the Hexclave dashboard, open the provider's settings, switch from shared keys to custom keys, and enter the client ID and client secret. ## Email server -For development, Stack uses a shared email server, which sends emails from Stack's domain. This is not ideal for production as users may not trust emails from an unfamiliar domain. You should set up an email server connected to your own domain. +For development, Hexclave uses a shared email server, which sends emails from Hexclave's domain. This is not ideal for production as users may not trust emails from an unfamiliar domain. You should set up an email server connected to your own domain. -Steps to connect your own email server with Stack: +Steps to connect your own email server with Hexclave: -1. **Setup Email Server**: Configure your own email server and connect it to your domain (this step is beyond Stack's documentation scope). -2. **Configure Stack's Email Settings**: Navigate to the `Emails` section in the Stack dashboard, click `Edit` in the `Email Server` section, switch from `Shared` to `Custom SMTP server`, enter your SMTP configurations, and save. +1. **Setup Email Server**: Configure your own email server and connect it to your domain (this step is beyond Hexclave's documentation scope). +2. **Configure Hexclave's Email Settings**: Navigate to the `Emails` section in the Hexclave dashboard, click `Edit` in the `Email Server` section, switch from `Shared` to `Custom SMTP server`, enter your SMTP configurations, and save. ## Enabling production mode -After completing the steps above, you can enable production mode on the `Project Settings` tab in the Stack dashboard, ensuring that your website runs securely with Stack in a production environment. +After completing the steps above, you can enable production mode on the `Project Settings` tab in the Hexclave dashboard, ensuring that your website runs securely with Hexclave in a production environment. diff --git a/docs-mintlify/guides/apps/payments/overview.mdx b/docs-mintlify/guides/apps/payments/overview.mdx index 3e5e5ac2e..6988f84dc 100644 --- a/docs-mintlify/guides/apps/payments/overview.mdx +++ b/docs-mintlify/guides/apps/payments/overview.mdx @@ -98,10 +98,10 @@ To sell a product, generate a checkout URL and redirect the user to it. The `cre
```typescript title="app/purchase/page.tsx" - import { stackServerApp } from "@/stack/server"; + import { hexclaveServerApp } from "@/hexclave/server"; export default async function PurchasePage() { - const user = await stackServerApp.getUser({ or: 'redirect' }); + const user = await hexclaveServerApp.getUser({ or: 'redirect' }); const checkoutUrl = await user.createCheckoutUrl({ productId: "prod_premium_monthly", @@ -199,10 +199,10 @@ export default function CreditsWidget() { When your app needs to consume credits (e.g. when a user sends an AI request), use `tryDecreaseQuantity` on the server. It's atomic and race-condition-safe - it will return `false` and do nothing if the balance would go negative. ```typescript title="lib/credits.ts" -import { stackServerApp } from "@/stack/server"; +import { hexclaveServerApp } from "@/hexclave/server"; export async function consumeCredits(userId: string, amount: number) { - const user = await stackServerApp.getUser(userId); + const user = await hexclaveServerApp.getUser(userId); if (!user) throw new Error("User not found"); const credits = await user.getItem("credits"); @@ -278,10 +278,10 @@ export default function UpgradeButton() { ```typescript // Cancel for the current user - await stackServerApp.cancelSubscription({ productId: "prod_pro" }); + await hexclaveServerApp.cancelSubscription({ productId: "prod_pro" }); // Cancel for a team - await stackServerApp.cancelSubscription({ + await hexclaveServerApp.cancelSubscription({ productId: "prod_team_plan", teamId: "team-id", }); @@ -353,19 +353,19 @@ Sometimes you need to give a customer a product without going through checkout - ```typescript // Grant a pre-configured product to a user -await stackServerApp.grantProduct({ +await hexclaveServerApp.grantProduct({ userId: "user-id", productId: "prod_premium", }); // Grant to a team -await stackServerApp.grantProduct({ +await hexclaveServerApp.grantProduct({ teamId: "team-id", productId: "prod_team_plan", }); // Grant to a custom customer -await stackServerApp.grantProduct({ +await hexclaveServerApp.grantProduct({ customCustomerId: "external-org-123", productId: "prod_enterprise", }); @@ -374,7 +374,7 @@ await stackServerApp.grantProduct({ You can also grant products with an **inline definition** - no pre-configured product needed. This is useful for one-off grants like bonus credits: ```typescript -await stackServerApp.grantProduct({ +await hexclaveServerApp.grantProduct({ userId: "user-id", product: { display_name: "Bonus Credits", @@ -403,7 +403,7 @@ Hexclave supports three types of payment customers: - **Teams** - Team or organization accounts. Team admins can create checkouts, switch plans, and cancel subscriptions for their team. - **Custom customers** - External entities identified by an arbitrary string ID. Useful for integrations with external systems. Custom customers can only be managed via the server SDK and do not support billing or invoices. -All payment methods (`createCheckoutUrl`, `useProducts`, `useItem`, `switchSubscription`, `useBilling`, `useInvoices`, etc.) are available on both user and team objects. For custom customers, use the top-level `stackServerApp` methods with `customCustomerId`. +All payment methods (`createCheckoutUrl`, `useProducts`, `useItem`, `switchSubscription`, `useBilling`, `useInvoices`, etc.) are available on both user and team objects. For custom customers, use the top-level `hexclaveServerApp` methods with `customCustomerId`. ## Payment emails @@ -424,7 +424,7 @@ Use your Stripe dashboard for payout schedules, bank-account settings, and accou During development, enable **test mode** in **Payments → Settings** in the dashboard. All purchases will be free and no real money is charged — products are granted immediately without going through Stripe. -When you're ready to test with real Stripe flows (but still using test credentials), disable Stack's test mode and use Stripe's test card numbers: +When you're ready to test with real Stripe flows (but still using test credentials), disable Hexclave's test mode and use Stripe's test card numbers: - **Success**: `4242 4242 4242 4242` - **Decline**: `4000 0000 0000 0002` diff --git a/docs-mintlify/guides/apps/rbac/overview.mdx b/docs-mintlify/guides/apps/rbac/overview.mdx index d89a07df4..9cd73d04f 100644 --- a/docs-mintlify/guides/apps/rbac/overview.mdx +++ b/docs-mintlify/guides/apps/rbac/overview.mdx @@ -5,11 +5,11 @@ sidebarTitle: RBAC icon: "/images/app-icons/rbac.svg" --- -Permissions are a way to control what each user can do and access within your application. Stack Auth RBAC lets you define reusable permission IDs in the dashboard, compose them into higher-level roles, assign team permissions to team members, and check permissions from the SDK. +Permissions are a way to control what each user can do and access within your application. Hexclave RBAC lets you define reusable permission IDs in the dashboard, compose them into higher-level roles, assign team permissions to team members, and check permissions from the SDK. ## Permission Types -Stack supports two types of permissions: +Hexclave supports two types of permissions: 1. **Team Permissions**: Control what a user can do within a specific team 2. **Project Permissions**: Control what a user can do globally, across the entire project @@ -64,7 +64,7 @@ Deleting a permission removes the definition, removes it from users who had it d ### System permissions -Stack comes with predefined team permissions known as system permissions. These IDs start with `$`. +Hexclave comes with predefined team permissions known as system permissions. These IDs start with `$`. System permissions: @@ -87,17 +87,17 @@ The member permissions dialog shows the same nested permission checklist. The me ## Team Permissions -Team permissions control what a user can do within each team. You can create and assign permissions to team members from the Stack dashboard. These permissions could include actions like `create_post` or `read_secret_info`, or roles like `admin` or `moderator`. Within your app, you can verify if a user has a specific permission within a team. +Team permissions control what a user can do within each team. You can create and assign permissions to team members from the Hexclave dashboard. These permissions could include actions like `create_post` or `read_secret_info`, or roles like `admin` or `moderator`. Within your app, you can verify if a user has a specific permission within a team. Permissions can be nested to create a hierarchical structure. For example, an `admin` permission can include both `moderator` and `user` permissions. We provide tools to help you verify whether a user has a permission directly or indirectly. ### Creating a Permission -To create a new permission, navigate to **RBAC -> Team Permissions** in the Stack dashboard. Click **Create Permission**, set the permission ID, optionally add a description, and choose any contained permissions. Any permissions included within these selected permissions will also be recursively included. +To create a new permission, navigate to **RBAC -> Team Permissions** in the Hexclave dashboard. Click **Create Permission**, set the permission ID, optionally add a description, and choose any contained permissions. Any permissions included within these selected permissions will also be recursively included. ### System Permissions -Stack comes with a few predefined team permissions known as system permissions. These permissions start with a dollar sign (`$`). While you can assign these permissions to members or include them within other permissions, you cannot modify them as they are integral to the Stack backend system. +Hexclave comes with a few predefined team permissions known as system permissions. These permissions start with a dollar sign (`$`). While you can assign these permissions to members or include them within other permissions, you cannot modify them as they are integral to the Hexclave backend system. ### Checking if a User has a Permission @@ -125,11 +125,11 @@ To check whether a user has a specific permission within a team, use `hasPermiss ```tsx title="Check user permission on the server" - import { stackServerApp } from "@/stack/server"; + import { hexclaveServerApp } from "@/hexclave/server"; export default async function CheckUserPermission() { - const user = await stackServerApp.getUser({ or: 'redirect' }); - const team = await stackServerApp.getTeam('some-team-id'); + const user = await hexclaveServerApp.getUser({ or: 'redirect' }); + const team = await hexclaveServerApp.getTeam('some-team-id'); const permission = await user.getPermission(team, 'read'); // This is a server-side check, so it's secure. @@ -146,11 +146,11 @@ To check whether a user has a specific permission within a team, use `hasPermiss For authorization logic, prefer a boolean server-side check: ```tsx title="app/api/team-settings/route.ts" -import { stackServerApp } from "@/stack/server"; +import { hexclaveServerApp } from "@/hexclave/server"; export async function POST() { - const user = await stackServerApp.getUser({ or: "redirect" }); - const team = await stackServerApp.getTeam("some-team-id"); + const user = await hexclaveServerApp.getUser({ or: "redirect" }); + const team = await hexclaveServerApp.getTeam("some-team-id"); if (!team || !(await user.hasPermission(team, "team:settings:update"))) { return new Response("Forbidden", { status: 403 }); @@ -188,11 +188,11 @@ To get a list of all permissions a user has in a team, use the `listPermissions` ```tsx title="List user permissions on the server" - import { stackServerApp } from "@/stack/server"; + import { hexclaveServerApp } from "@/hexclave/server"; export default async function DisplayUserPermissions() { - const user = await stackServerApp.getUser({ or: 'redirect' }); - const team = await stackServerApp.getTeam('some-team-id'); + const user = await hexclaveServerApp.getUser({ or: 'redirect' }); + const team = await hexclaveServerApp.getTeam('some-team-id'); const permissions = team ? await user.listPermissions(team) : []; return ( @@ -212,8 +212,8 @@ To get a list of all permissions a user has in a team, use the `listPermissions` To grant a permission to a user, use the `grantPermission` method on the `ServerUser`. Here's an example: ```tsx -const team = await stackServerApp.getTeam('teamId'); -const user = await stackServerApp.getUser(); +const team = await hexclaveServerApp.getTeam('teamId'); +const user = await hexclaveServerApp.getUser(); if (!team || !user) throw new Error("Team or user not found"); await user.grantPermission(team, 'read'); ``` @@ -223,8 +223,8 @@ await user.grantPermission(team, 'read'); To revoke a permission from a user, use the `revokePermission` method on the `ServerUser`. Here's an example: ```tsx -const team = await stackServerApp.getTeam('teamId'); -const user = await stackServerApp.getUser(); +const team = await hexclaveServerApp.getTeam('teamId'); +const user = await hexclaveServerApp.getUser(); if (!team || !user) throw new Error("Team or user not found"); await user.revokePermission(team, 'read'); ``` @@ -235,7 +235,7 @@ Project permissions are global permissions that apply to a user across the entir ### Creating a Project Permission -To create a new project permission, navigate to **RBAC -> Project Permissions** in the Stack dashboard. Similar to team permissions, you can set an ID, add a description, and select other project permissions that the new permission contains. +To create a new project permission, navigate to **RBAC -> Project Permissions** in the Hexclave dashboard. Similar to team permissions, you can set an ID, add a description, and select other project permissions that the new permission contains. ### Checking if a User has a Project Permission @@ -261,10 +261,10 @@ To check whether a user has a specific project permission, use `hasPermission`, ```tsx title="Check user permission on the server" - import { stackServerApp } from "@/stack/server"; + import { hexclaveServerApp } from "@/hexclave/server"; export default async function CheckGlobalPermission() { - const user = await stackServerApp.getUser({ or: 'redirect' }); + const user = await hexclaveServerApp.getUser({ or: 'redirect' }); const permission = await user.getPermission('access_admin_dashboard'); return ( @@ -280,10 +280,10 @@ To check whether a user has a specific project permission, use `hasPermission`, For authorization logic, prefer a server-side boolean check: ```tsx title="app/admin/page.tsx" -import { stackServerApp } from "@/stack/server"; +import { hexclaveServerApp } from "@/hexclave/server"; export default async function AdminPage() { - const user = await stackServerApp.getUser({ or: "redirect" }); + const user = await hexclaveServerApp.getUser({ or: "redirect" }); const canAccessAdmin = await user.hasPermission("access_admin_dashboard"); if (!canAccessAdmin) { @@ -320,10 +320,10 @@ To get a list of all global permissions a user has, use the `listPermissions` me ```tsx title="List global permissions on the server" - import { stackServerApp } from "@/stack/server"; + import { hexclaveServerApp } from "@/hexclave/server"; export default async function DisplayGlobalPermissions() { - const user = await stackServerApp.getUser({ or: 'redirect' }); + const user = await hexclaveServerApp.getUser({ or: 'redirect' }); const permissions = await user.listPermissions(); return ( @@ -349,7 +349,7 @@ const directPermissions = await user.listPermissions({ recursive: false }); To grant a global permission to a user, use the `grantPermission` method: ```tsx -const user = await stackServerApp.getUser(); +const user = await hexclaveServerApp.getUser(); if (!user) throw new Error("User not found"); await user.grantPermission('access_admin_dashboard'); ``` @@ -359,7 +359,7 @@ await user.grantPermission('access_admin_dashboard'); To revoke a global permission from a user, use the `revokePermission` method: ```tsx -const user = await stackServerApp.getUser(); +const user = await hexclaveServerApp.getUser(); if (!user) throw new Error("User not found"); await user.revokePermission('access_admin_dashboard'); ``` @@ -381,4 +381,4 @@ const allPermissions = await user.listPermissions(team); const directPermissions = await user.listPermissions(team, { recursive: false }); ``` -For checks like `hasPermission` and `getPermission`, Stack resolves contained permissions recursively so roles work as expected. +For checks like `hasPermission` and `getPermission`, Hexclave resolves contained permissions recursively so roles work as expected. diff --git a/docs-mintlify/guides/apps/teams/overview.mdx b/docs-mintlify/guides/apps/teams/overview.mdx index b2b48a7a0..4e6fcbc4d 100644 --- a/docs-mintlify/guides/apps/teams/overview.mdx +++ b/docs-mintlify/guides/apps/teams/overview.mdx @@ -185,7 +185,7 @@ if (!hasPermission) { Always enforce authorization on the server for business logic: ```tsx -const user = await stackServerApp.getUser({ or: "redirect" }); +const user = await hexclaveServerApp.getUser({ or: "redirect" }); const team = await user.getTeam("some-team-id"); if (!team || !(await user.hasPermission(team, "$invite_members"))) { @@ -207,7 +207,7 @@ You can list all teams a user belongs to using `listTeams` or `useTeams`, or fet ```tsx "use client"; - import { useUser } from "@stackframe/stack"; + import { useUser } from "@hexclave/next"; export function TeamList() { const user = useUser({ or: "redirect" }); @@ -231,10 +231,10 @@ You can list all teams a user belongs to using `listTeams` or `useTeams`, or fet ```tsx - import { stackServerApp } from "@/stack/server"; + import { hexclaveServerApp } from "@/hexclave/server"; export default async function TeamList() { - const user = await stackServerApp.getUser({ or: "redirect" }); + const user = await hexclaveServerApp.getUser({ or: "redirect" }); const allTeams = await user.listTeams(); const someTeam = await user.getTeam("some-team-id"); @@ -270,7 +270,7 @@ const team = await user.createTeam({ To create a team on the server without adding a specific user, use `createTeam` on the server app: ```tsx -const team = await stackServerApp.createTeam({ +const team = await hexclaveServerApp.createTeam({ displayName: "New Team", }); ``` @@ -477,7 +477,7 @@ You can list all teams a user belongs to using the `listTeams` or `useTeams` fun ```tsx - const user = await stackServerApp.getUser({ or: 'redirect' }); + const user = await hexclaveServerApp.getUser({ or: 'redirect' }); const allTeams = await user.listTeams(); const someTeam = await user.getTeam('some-team-id'); // May be null if the user is not a member of this team @@ -496,9 +496,9 @@ You can list all teams a user belongs to using the `listTeams` or `useTeams` fun ## Creating a team -To create a team, use the `createTeam` function on the `User` object. The user will be added to the team with the default team creator permissions (You can change this on the permissions tab in the Stack dashboard). +To create a team, use the `createTeam` function on the `User` object. The user will be added to the team with the default team creator permissions (You can change this on the permissions tab in the Hexclave dashboard). -On the client side, this requires enabling the "client side team creation" on the team settings tab in the Stack dashboard. +On the client side, this requires enabling the "client side team creation" on the team settings tab in the Hexclave dashboard. ```jsx const team = await user.createTeam({ @@ -509,7 +509,7 @@ const team = await user.createTeam({ To create a team on the server without adding a specific user, use the `createTeam` function on the `ServerApp` object: ```jsx -const team = await stackServerApp.createTeam({ +const team = await hexclaveServerApp.createTeam({ displayName: 'New Team', }); ``` diff --git a/docs-mintlify/guides/apps/teams/team-selection.mdx b/docs-mintlify/guides/apps/teams/team-selection.mdx index f002281a9..20398b63e 100644 --- a/docs-mintlify/guides/apps/teams/team-selection.mdx +++ b/docs-mintlify/guides/apps/teams/team-selection.mdx @@ -19,7 +19,7 @@ While the current team method can be simpler to implement, it has a downside. If ## Selected Team Switcher -To facilitate team selection, Stack provides a component that looks like this: +To facilitate team selection, Hexclave provides a component that looks like this: TeamSwitcher @@ -144,7 +144,7 @@ Some apps let users work either personally or inside a team. Use `allowNull` to ```tsx "use client"; -import { SelectedTeamSwitcher, useUser } from "@stackframe/stack"; +import { SelectedTeamSwitcher, useUser } from "@hexclave/next"; export function ScopeSwitcher() { const user = useUser({ or: "redirect" }); diff --git a/docs-mintlify/guides/apps/webhooks/overview.mdx b/docs-mintlify/guides/apps/webhooks/overview.mdx index b04d144aa..7f2f42889 100644 --- a/docs-mintlify/guides/apps/webhooks/overview.mdx +++ b/docs-mintlify/guides/apps/webhooks/overview.mdx @@ -1,16 +1,16 @@ --- title: "Webhooks" -description: "Receive real-time updates when events occur in your Stack project" +description: "Receive real-time updates when events occur in your Hexclave project" icon: "/images/app-icons/webhooks.svg" --- -Webhooks are a powerful way to keep your backend in sync with Stack. They allow you to receive real-time updates when events occur in your Stack project, such as when a user or team is created, updated, or deleted. +Webhooks are a powerful way to keep your backend in sync with Hexclave. They allow you to receive real-time updates when events occur in your Hexclave project, such as when a user or team is created, updated, or deleted. For payload schemas and generated webhook event references, see the [webhook API reference](/api/webhooks/users/usercreated). ## Setting up webhooks -In the Stack dashboard, you can create a webhook endpoint in the "Webhooks" section. After creating this endpoint with your server URL, you will start receiving POST requests with a JSON payload at that endpoint. The event payload will look something like this: +In the Hexclave dashboard, you can create a webhook endpoint in the "Webhooks" section. After creating this endpoint with your server URL, you will start receiving POST requests with a JSON payload at that endpoint. The event payload will look something like this: ```json { @@ -39,7 +39,7 @@ The **Webhooks** dashboard page embeds the endpoint manager where you create end The main Webhooks page shows your webhook endpoints. Each endpoint includes: -- **Endpoint URL** - The URL Stack sends events to. +- **Endpoint URL** - The URL Hexclave sends events to. - **Description** - Optional label for your own reference. - **Status** - **Active** or **Disabled**. - **Actions** - View details, test, edit, or delete the endpoint. @@ -69,12 +69,16 @@ Endpoint rows have a **Test** action, and newly-created endpoints can be tested { "type": "stack.test", "data": { - "message": "Stack webhook test event triggered from the Stack dashboard.", + "message": "Hexclave webhook test event triggered from the Hexclave dashboard.", "endpointUrl": "https://example.com/api/webhooks/stack" } } ``` + + Test events still use the legacy `stack.test` event type for backward compatibility. In your own integration code, prefer `HEXCLAVE_WEBHOOK_SECRET` and the current Hexclave naming — but legacy `STACK_WEBHOOK_SECRET`, `x-stack-*` request headers, and other Stack Auth-era identifiers remain accepted by the API. See [Migrating from Stack Auth to Hexclave](/migration). + + Click **Send test event** to send it. On success, the dashboard confirms that the event was sent and the endpoint is ready. On failure, it shows the delivery error returned by the webhook service. ### Editing and deleting endpoints @@ -94,7 +98,7 @@ The endpoint detail page shows: - **Description** - The saved description, or `-` when empty. - **Verification Secret** - The endpoint signing secret, with a copy button. -Use the verification secret as `STACK_WEBHOOK_SECRET` (or your own secret environment variable name) in your webhook receiver. Do not expose it to the browser. +Use the verification secret as `HEXCLAVE_WEBHOOK_SECRET` (or your own secret environment variable name) in your webhook receiver. Do not expose it to the browser. ### Event history @@ -112,9 +116,9 @@ You can use services like [Svix Playground](https://www.svix.com/play/) or [Webh ## Verifying webhooks -To ensure the webhook is coming from Stack (and not from a malicious actor) and is not prone to replay attacks, you should verify the request. +To ensure the webhook is coming from Hexclave (and not from a malicious actor) and is not prone to replay attacks, you should verify the request. -Stack signs the webhook payload with a secret key that you can find in the endpoint details on the dashboard. You can verify the signature using the Svix client library. Check out the [Svix documentation](https://docs.svix.com/receiving/verifying-payloads/how) for instructions on how to verify the signature in JavaScript, Python, Ruby, and other languages. Here are example handlers across the supported frameworks: +Hexclave signs the webhook payload with a secret key that you can find in the endpoint details on the dashboard. You can verify the signature using the Svix client library. Check out the [Svix documentation](https://docs.svix.com/receiving/verifying-payloads/how) for instructions on how to verify the signature in JavaScript, Python, Ruby, and other languages. Here are example handlers across the supported frameworks: ```tsx Next.js @@ -122,7 +126,7 @@ Stack signs the webhook payload with a secret key that you can find in the endpo import { Webhook } from "svix"; export async function POST(request: Request) { - const secret = process.env.STACK_WEBHOOK_SECRET!; + const secret = process.env.HEXCLAVE_WEBHOOK_SECRET!; const payload = await request.text(); const headers = { "svix-id": request.headers.get("svix-id") ?? "", @@ -148,7 +152,7 @@ const app = express(); app.use("/api/webhooks/stack", express.text({ type: "application/json" })); app.post("/api/webhooks/stack", (req, res) => { - const wh = new Webhook(process.env.STACK_WEBHOOK_SECRET!); + const wh = new Webhook(process.env.HEXCLAVE_WEBHOOK_SECRET!); const verifiedPayload = wh.verify(req.body, { "svix-id": req.header("svix-id") ?? "", "svix-timestamp": req.header("svix-timestamp") ?? "", @@ -167,7 +171,7 @@ const app = express(); app.use("/api/webhooks/stack", express.text({ type: "application/json" })); app.post("/api/webhooks/stack", (req, res) => { - const wh = new Webhook(process.env.STACK_WEBHOOK_SECRET); + const wh = new Webhook(process.env.HEXCLAVE_WEBHOOK_SECRET); const verifiedPayload = wh.verify(req.body, { "svix-id": req.header("svix-id") ?? "", "svix-timestamp": req.header("svix-timestamp") ?? "", @@ -198,7 +202,7 @@ createServer(async (req, res) => { req.on("error", reject); }); - const wh = new Webhook(process.env.STACK_WEBHOOK_SECRET); + const wh = new Webhook(process.env.HEXCLAVE_WEBHOOK_SECRET); const verifiedPayload = wh.verify(payload, { "svix-id": req.headers["svix-id"] ?? "", "svix-timestamp": req.headers["svix-timestamp"] ?? "", @@ -232,7 +236,7 @@ createServer(async (req, res) => { req.on("error", reject); }); - const wh = new Webhook(process.env.STACK_WEBHOOK_SECRET); + const wh = new Webhook(process.env.HEXCLAVE_WEBHOOK_SECRET); const verifiedPayload = wh.verify(payload, { "svix-id": req.headers["svix-id"] ?? "", "svix-timestamp": req.headers["svix-timestamp"] ?? "", @@ -252,8 +256,8 @@ from svix.webhooks import Webhook @csrf_exempt -def stack_webhook(request): - wh = Webhook(settings.STACK_WEBHOOK_SECRET) +def hexclave_webhook(request): + wh = Webhook(settings.HEXCLAVE_WEBHOOK_SECRET) verified_payload = wh.verify( request.body.decode("utf-8"), { @@ -273,13 +277,13 @@ from fastapi import FastAPI, Request from svix.webhooks import Webhook app = FastAPI() -STACK_WEBHOOK_SECRET = os.environ["STACK_WEBHOOK_SECRET"] +HEXCLAVE_WEBHOOK_SECRET = os.environ["HEXCLAVE_WEBHOOK_SECRET"] @app.post("/api/webhooks/stack") -async def stack_webhook(request: Request): +async def hexclave_webhook(request: Request): payload = await request.body() - wh = Webhook(STACK_WEBHOOK_SECRET) + wh = Webhook(HEXCLAVE_WEBHOOK_SECRET) verified_payload = wh.verify( payload.decode("utf-8"), { @@ -299,12 +303,12 @@ from flask import Flask, jsonify, request from svix.webhooks import Webhook app = Flask(__name__) -STACK_WEBHOOK_SECRET = os.environ["STACK_WEBHOOK_SECRET"] +HEXCLAVE_WEBHOOK_SECRET = os.environ["HEXCLAVE_WEBHOOK_SECRET"] @app.post("/api/webhooks/stack") -def stack_webhook(): - wh = Webhook(STACK_WEBHOOK_SECRET) +def hexclave_webhook(): + wh = Webhook(HEXCLAVE_WEBHOOK_SECRET) verified_payload = wh.verify( request.get_data(as_text=True), {