# Пријавите се помоћу Beeuni

Ограничите приступ својој апликацији помоћу Beeuni идентитета уз једну руту и делујте у име пријављеног корисника путем SDK-а.

Canonical page: https://beeuni.ai/docs/sr/sdk/sign-in

„Пријављивање преко Beeuni“ чини Beeuni добављачем идентитета за апликацију коју покрећете:
контролну таблу, интерни алат или специјализован производ изграђен на Beeuni. Корисници
се пријављују својим Beeuni налогом, ваш сервер зна ко су, а сваки
Beeuni позив из ваше апликације извршава се као тај корисник, са његовим
додељеним улогама. Цео ток је у `@beeuni/sdk`. Ваша апликација никада не чува
Beeuni токен у прегледачу.

То је стандардни OAuth 2.1 (ауторизациони код + PKCE) који Beeuni API пружа
на `api.beeuni.ai`.

> Правите апликацију **коју хостује Beeuni** (`*.apps.beeuni.ai`)? Ништа од
> овога вам није потребно. Контрола приступа апликацијама већ је потврдила идентитет посетиоца — прочитајте га помоћу
> `beeuniAppViewerToken()` / `readAppViewer()` и преузмите токене за пријављивање за
> апликацију или апликацију коју она користи помоћу `beeuniToken()`. Погледајте
> [Токени за пријављивање за апликације](#sign-in-tokens-for-apps) испод.

<a id="1-register-your-app"></a>

## 1. Региструјте своју апликацију

Идите на **Account → Tokens → OAuth apps → Register app** или позовите SDK:

```ts
const app = await beeuni.iam.oauthClients.create(accountId, {
  name: 'Dashboards',
  client_type: 'confidential',            // 'public' for a browser/native app (PKCE only, no secret)
  redirect_uris: ['https://dashboards.example.com/api/beeuni/auth/callback'],
  scopes: ['profile', 'email', 'beeuni'],
});
// app.client_id, app.client_secret (shown once)
```

За регистрацију је потребно `token.create` на налогу. URI адресе за преусмеравање пореде се
бајт по бајт; `https` је обавезан осим на `localhost`.

| Опсег | Омогућава апликацији |
|---|---|
| `profile` | ID корисника, адресу е-поште и чланства у налозима (`GET /v1/accounts/me`). |
| `email` | Адресу е-поште (алијас за клијенте који прате OIDC структуру). |
| `beeuni` | Деловање као корисник на целом Beeuni API-ју — пројекти, сесије, датотеке, IAM провере. Без тога токен служи само за идентитет. |

<a id="2-mount-the-handler"></a>

## 2. Повежите обрађивач

```ts
// lib/beeuni-auth.ts
import { createBeeuniAuth } from '@beeuni/sdk/server';

export const auth = createBeeuniAuth({
  backendUrl: 'https://api.beeuni.ai/v1',
  clientId: process.env.BEEUNI_OAUTH_CLIENT_ID!,
  clientSecret: process.env.BEEUNI_OAUTH_CLIENT_SECRET,   // omit for a public client
  redirectUri: 'https://dashboards.example.com/api/beeuni/auth/callback',
  cookieSecret: process.env.BEEUNI_AUTH_COOKIE_SECRET!,   // ≥ 32 chars; encrypts the session cookie
});
```

```ts
// app/api/beeuni/auth/[...beeuni]/route.ts  (Next.js App Router)
import { auth } from '@/lib/beeuni-auth';
const handle = (request: Request) => auth.handler(request);
export { handle as GET, handle as POST };
```

Обрађивач опслужује сваку руту под `basePath` (изведено из URI адресе
за преусмеравање — `/api/beeuni/auth` изнад):

| Путања | Радња |
|---|---|
| `/signin?return_to=/path` | Покреће пријављивање (PKCE S256 + стање у колачићу који траје 10 минута) и преусмерава на Beeuni. |
| `/callback` | Размењује код, поставља шифровани колачић сесије `HttpOnly` и преусмерава на `return_to`. |
| `/refresh?return_to=` | Ротира пар токена и преусмерава. Користи га `requireViewer`. |
| `/signout?return_to=` | Опозива токен за освежавање у Beeuni и брише колачић. |
| `/me` | Посетилац као JSON или `401`. Освежава токен током обраде ако је приступни токен истекао. |
| `/proxy/*` | Прослеђује Beeuni API-ју као посетилац. `backendUrl` SDK-а за прегледач. |

`return_to` је увек ограничен на путању истог порекла.

<a id="3-gate-pages-and-act-as-the-user"></a>

## 3. Ограничите приступ страницама и делујте као корисник

```ts
// middleware.ts — every page needs a viewer
import { auth } from '@/lib/beeuni-auth';

export async function middleware(request: Request) {
  const gate = await auth.requireViewer(request);
  if (gate.response) return gate.response;   // 302 → /refresh or /signin
}
export const config = { matcher: ['/((?!api/beeuni/auth|_next).*)'] };
```

```ts
// a server component / route handler
const viewer = await auth.viewer(request);       // { userId, email, accounts, scopes, token, expiresAt } | null
const beeuni = await auth.beeuni(request);       // request-scoped client acting as the viewer
const projects = await beeuni.projects.list();
const allowed = await beeuni.iam.can(accountId, viewer!.userId, { action: 'project.write', resourceType: 'project', resourceId });
```

`viewer()` служи само за читање и никада не троши једнократни токен за освежавање; користите
`requireViewer()` у посредничком слоју да се страница никада не прикаже као за одјављеног корисника
ако је његов токен за освежавање још важећи.

<a id="4-the-browser"></a>

## 4. Прегледач

```tsx
import { createBeeuni } from '@beeuni/sdk';
import { SignInWithBeeuni, useBeeuniViewer } from '@beeuni/sdk/react';

const beeuni = createBeeuni(auth.clientConfig());   // backendUrl = '/api/beeuni/auth/proxy'

function Header() {
  const { status, viewer } = useBeeuniViewer();
  if (status === 'signed-in') return <span>{viewer.email}</span>;
  return <SignInWithBeeuni className="button" />;
}
```

Клијент у прегледачу шаље заменски bearer токен; `/proxy` га на серверу замењује
стварним токеном посетиоца. `useSession`, `beeuni.project(id).sessions.*` и
сви остали SDK позиви раде непромењено преко њега.

<a id="what-the-user-sees"></a>

## Шта корисник види

Први пут Beeuni приказује екран за сагласност са називом ваше апликације и опсезима.
Beeuni памти одлуку за сваког корисника и апликацију, па каснија пријављивања преусмеравају
директно назад. Опозив апликације брише сваки токен који је издала.

<a id="discovery"></a>

## Откривање

`GET https://api.beeuni.ai/.well-known/oauth-authorization-server` (такође
под `/v1/oauth/.well-known/…`) објављује крајње тачке за општи OAuth
клијент. SDK-у то није потребно — сваку крајњу тачку изводи из `backendUrl`.

<a id="sign-in-tokens-for-apps"></a>

## Токени за пријављивање за апликације

Код у апликацији коју хостује Beeuni и апликацијама које она користи прихвата другу врсту
токена: кратак ES256 JWT који Beeuni издаје за једну апликацију. Без OAuth тока, без
преусмеравања, без тајне клијента.

| | Вредност |
|---|---|
| Издавалац | `<API origin>/v1/projects/<projectId>`, један по пројекту |
| Откривање | `<issuer>/.well-known/openid-configuration` и `<issuer>/jwks.json`, јавно |
| Публика | ID апликације којој је токен намењен |
| Рок важења | 15 минута |
| Тврдње | `sub`, `email`, `name`, `picture`, `groups`, `group_ids`, `role`, `account_id`, `project_id`; токен агента додаје `kind: "agent"` и нема групе ни улогу |

Свака апликација садржи вредности за проверу својих токена: `app.auth.issuer`,
`app.auth.audience`, `app.auth.jwks_uri`.

```ts
import { beeuniToken, beeuniBinding, verifyBeeuniToken, requireBeeuniMember } from '@beeuni/sdk';

// In the App's browser code: a token fetcher for this App, or an App it uses.
const forThisApp = beeuniToken();
const forDb = beeuniToken({ audience: 'db' });
const db = beeuniBinding('db');   // { url: '<origin>/_beeuni/apps/db', token: forDb }

// On a server that receives the token:
const member = await verifyBeeuniToken(bearer, {
  issuer: app.auth.issuer,
  audience: app.auth.audience,
  jwks: app.auth.jwks_uri,
});
requireBeeuniMember(member, { roles: ['owner', 'admin'] });
```

У серверској апликацији Beeuni убацује `BEEUNI_AUTH_ISSUER` (издаваоца пројекта),
`BEEUNI_AUTH_AUDIENCE` (ID саме апликације) и `BEEUNI_AUTH_JWKS` (скуп кључева
пројекта, као `data:` URI), па `verifyBeeuniToken(bearer)` не захтева опције.
Немојте сами постављати `BEEUNI_AUTH_*`: префикс `BEEUNI_` је резервисан и
`beeuni validate` га одбија.

`verifyBeeuniToken` одбија токен када публика није постављена (опција или
`BEEUNI_AUTH_AUDIENCE`): један кључ пројекта потписује токене сваке апликације у
пројекту, па `aud` спречава прихватање токена друге апликације. Проследите
`audience: false` само ако желите да прихватите токен за било коју апликацију пројекта.

`beeuniToken` чита `GET /_beeuni/token?audience=<slug or id>` на сопственом
пореклу апликације. Публика је сама апликација (подразумевано) или апликација коју она користи
(`beeuni apps link <app> --uses <other>`); за било коју другу одговор је
`403 app_not_linked`. Члан, скрипта или агент уместо тога издаје токен преко API-ја:
`beeuni.project(projectId).apps.token(appId)` или
`beeuni apps token <app>`. Потпун уговор, повезивање веза и
подешавање Convex позадинског система: [SDK → Апликације](/docs/sr/sdk/apps) и
[Апликације → Апликације које апликација користи](/docs/sr/feature-flags/apps#apps-an-app-uses-sign-in-tokens-and-bindings).
