mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-13 21:01:21 +08:00
Merge dev into added_docs
This commit is contained in:
commit
daab72c048
2
.github/workflows/docker-server-build.yaml
vendored
2
.github/workflows/docker-server-build.yaml
vendored
@ -13,7 +13,7 @@ concurrency:
|
||||
jobs:
|
||||
build-server:
|
||||
name: Docker Build and Push Server
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubicloud-standard-8
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
56
docs/public/stack-auth-cli-template.py
Normal file
56
docs/public/stack-auth-cli-template.py
Normal file
@ -0,0 +1,56 @@
|
||||
import time
|
||||
import requests
|
||||
import webbrowser
|
||||
import urllib.parse
|
||||
|
||||
def prompt_cli_login(
|
||||
*,
|
||||
base_url: str = "https://api.stack-auth.com",
|
||||
app_url: str,
|
||||
project_id: str,
|
||||
publishable_client_key: str,
|
||||
):
|
||||
if not app_url:
|
||||
raise Exception("app_url is required and must be set to the URL of the app you're authenticating with")
|
||||
if not project_id:
|
||||
raise Exception("project_id is required")
|
||||
if not publishable_client_key:
|
||||
raise Exception("publishable_client_key is required")
|
||||
|
||||
def post(endpoint, json):
|
||||
return requests.request(
|
||||
'POST',
|
||||
f'{base_url}{endpoint}',
|
||||
headers={
|
||||
'Content-Type': 'application/json',
|
||||
'x-stack-project-id': project_id,
|
||||
'x-stack-access-type': 'client',
|
||||
'x-stack-publishable-client-key': publishable_client_key,
|
||||
},
|
||||
json=json,
|
||||
)
|
||||
|
||||
# Step 1: Initiate the CLI auth process
|
||||
init = post('/api/v1/auth/cli', {
|
||||
'expires_in_millis': 10 * 60 * 1000,
|
||||
})
|
||||
if init.status_code != 200:
|
||||
raise Exception(f"Failed to initiate CLI auth: {init.status_code} {init.text}")
|
||||
polling_code = init.json()['polling_code']
|
||||
login_code = init.json()['login_code']
|
||||
|
||||
# Step 2: Open the browser for the user to authenticate
|
||||
url = f'{app_url}/handler/cli-auth-confirm?login_code={urllib.parse.quote(login_code)}'
|
||||
print(f"Opening browser to authenticate. If it doesn't open automatically, please visit:\n{url}")
|
||||
webbrowser.open(url)
|
||||
|
||||
# Step 3: Retrieve the token
|
||||
while True:
|
||||
status = post('/api/v1/auth/cli/poll', {
|
||||
'polling_code': polling_code,
|
||||
})
|
||||
if status.status_code != 200 and status.status_code != 201:
|
||||
raise Exception(f"Failed to get CLI auth status: {status.status_code} {status.text}")
|
||||
if status.json()['status'] == 'success':
|
||||
return status.json()['refresh_token']
|
||||
time.sleep(2)
|
||||
@ -247,56 +247,74 @@ export function ApiSidebarContent({ pages = [] }: { pages?: PageData[] }) {
|
||||
Overview
|
||||
</ApiSidebarLink>
|
||||
|
||||
{Object.entries(organizedPages).map(([sectionKey, section]) => (
|
||||
<div key={sectionKey} className="mb-4">
|
||||
<ApiSeparator>{section.title}</ApiSeparator>
|
||||
{Object.entries(organizedPages)
|
||||
.filter(([sectionKey]) => sectionKey !== 'admin') // Hide admin section from sidebar
|
||||
.sort(([aKey], [bKey]) => {
|
||||
// Define the desired order of sections
|
||||
const sectionOrder = ['client', 'server', 'webhooks'];
|
||||
const aIndex = sectionOrder.indexOf(aKey);
|
||||
const bIndex = sectionOrder.indexOf(bKey);
|
||||
// If both sections are in our defined order, sort by that order
|
||||
if (aIndex !== -1 && bIndex !== -1) {
|
||||
return aIndex - bIndex;
|
||||
}
|
||||
// If only one is in our defined order, prioritize it
|
||||
if (aIndex !== -1) return -1;
|
||||
if (bIndex !== -1) return 1;
|
||||
// If neither is in our defined order, sort alphabetically
|
||||
//eslint-disable-next-line
|
||||
return aKey.localeCompare(bKey);
|
||||
})
|
||||
.map(([sectionKey, section]) => (
|
||||
<div key={sectionKey} className="mb-4">
|
||||
<ApiSeparator>{section.title}</ApiSeparator>
|
||||
|
||||
{/* Section-level pages */}
|
||||
{section.pages.length > 0 && section.pages.map((page: PageData) => (
|
||||
<ApiSidebarLink
|
||||
key={page.url}
|
||||
href={page.url}
|
||||
method={getHttpMethod(page)}
|
||||
>
|
||||
{page.data.title || formatTitle(page.slugs[page.slugs.length - 1])}
|
||||
</ApiSidebarLink>
|
||||
))}
|
||||
{/* Section-level pages */}
|
||||
{section.pages.length > 0 && section.pages.map((page: PageData) => (
|
||||
<ApiSidebarLink
|
||||
key={page.url}
|
||||
href={page.url}
|
||||
method={getHttpMethod(page)}
|
||||
>
|
||||
{page.data.title || formatTitle(page.slugs[page.slugs.length - 1])}
|
||||
</ApiSidebarLink>
|
||||
))}
|
||||
|
||||
{/* Grouped pages */}
|
||||
{Object.entries(section.groups).map(([groupKey, group]: [string, OrganizedGroup]) => (
|
||||
<CollapsibleSection key={groupKey} title={group.title}>
|
||||
{group.pages.map((page: PageData) => {
|
||||
const method = getHttpMethod(page);
|
||||
const title = page.data.title || formatTitle(page.slugs[page.slugs.length - 1]);
|
||||
{/* Grouped pages */}
|
||||
{Object.entries(section.groups).map(([groupKey, group]: [string, OrganizedGroup]) => (
|
||||
<CollapsibleSection key={groupKey} title={group.title}>
|
||||
{group.pages.map((page: PageData) => {
|
||||
const method = getHttpMethod(page);
|
||||
const title = page.data.title || formatTitle(page.slugs[page.slugs.length - 1]);
|
||||
|
||||
// Special handling for webhooks (EVENT badge instead of HTTP method)
|
||||
if (sectionKey === 'webhooks') {
|
||||
return (
|
||||
<ApiSidebarLink key={page.url} href={page.url}>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="inline-flex items-center px-1 py-0.5 rounded text-xs font-medium border bg-purple-100 text-purple-800 border-purple-200 dark:bg-purple-900/30 dark:text-purple-300 dark:border-purple-700 leading-none">
|
||||
EVENT
|
||||
</span>
|
||||
<span>{title}</span>
|
||||
</div>
|
||||
</ApiSidebarLink>
|
||||
);
|
||||
}
|
||||
|
||||
// Special handling for webhooks (EVENT badge instead of HTTP method)
|
||||
if (sectionKey === 'webhooks') {
|
||||
return (
|
||||
<ApiSidebarLink key={page.url} href={page.url}>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="inline-flex items-center px-1 py-0.5 rounded text-xs font-medium border bg-purple-100 text-purple-800 border-purple-200 dark:bg-purple-900/30 dark:text-purple-300 dark:border-purple-700 leading-none">
|
||||
EVENT
|
||||
</span>
|
||||
<span>{title}</span>
|
||||
</div>
|
||||
<ApiSidebarLink
|
||||
key={page.url}
|
||||
href={page.url}
|
||||
method={method}
|
||||
>
|
||||
{title}
|
||||
</ApiSidebarLink>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ApiSidebarLink
|
||||
key={page.url}
|
||||
href={page.url}
|
||||
method={method}
|
||||
>
|
||||
{title}
|
||||
</ApiSidebarLink>
|
||||
);
|
||||
})}
|
||||
</CollapsibleSection>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
})}
|
||||
</CollapsibleSection>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</ScrollViewport>
|
||||
</ScrollArea>
|
||||
|
||||
|
||||
2
docs/templates/others/cli-authentication.mdx
vendored
2
docs/templates/others/cli-authentication.mdx
vendored
@ -5,7 +5,7 @@ description: How to authenticate a command line application using Stack Auth
|
||||
|
||||
If you're building a command line application that runs in a terminal, you can use Stack Auth to let your users log in to their accounts.
|
||||
|
||||
To do so, we provide a Python template that you can use as a starting point. [Download it here](https://github.com/stack-auth/stack-auth/tree/main/docs/examples/stack_auth_cli_template.py) and copy it into your project, for example:
|
||||
To do so, we provide a Python template that you can use as a starting point. [Download it here](https://github.com/stack-auth/stack-auth/tree/main/docs/public/stack_auth_cli_template.py) and copy it into your project, for example:
|
||||
|
||||
```py
|
||||
└─ my-python-app
|
||||
|
||||
Loading…
Reference in New Issue
Block a user