From 62229dd892546c49c9f76c2ca16f03f70fe80014 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Sat, 6 Jun 2026 10:53:08 +0530 Subject: [PATCH 1/2] docs(sdks): document FGA support in authorizer-go and authorizer-js Add fine-grained authorization (FGA) documentation to the SDK reference: - authorizer-js functions.md: new getPermissions section, required_permissions param rows + samples for getSession, validateJWTToken, validateSession - authorizer-go index.md: GetPermissions in available methods + FGA usage examples (RequiredPermissions and GetPermissions) --- docs/sdks/authorizer-go/index.md | 41 +++++++++++++-- docs/sdks/authorizer-js/functions.md | 78 +++++++++++++++++++++++++--- 2 files changed, 108 insertions(+), 11 deletions(-) diff --git a/docs/sdks/authorizer-go/index.md b/docs/sdks/authorizer-go/index.md index 64b4d76..7b962ad 100644 --- a/docs/sdks/authorizer-go/index.md +++ b/docs/sdks/authorizer-go/index.md @@ -78,6 +78,40 @@ if res.IsValid { } ``` +### Step 4: Fine-grained authorization (FGA) + +Authorizer supports `resource:scope` based fine-grained permissions. The SDK exposes them in two ways. + +**Assert required permissions while validating** -- pass `RequiredPermissions` to `ValidateJWTToken`, `ValidateSession` or `GetSession`. They are evaluated with AND semantics: every entry must be granted, otherwise the result is unauthorized. + +```go +res, err := authorizerClient.ValidateJWTToken(&authorizer.ValidateJWTTokenInput{ + TokenType: authorizer.TokenTypeAccessToken, + Token: "your-jwt-token", + RequiredPermissions: []*authorizer.PermissionInput{ + {Resource: "documents", Scope: "read"}, + {Resource: "documents", Scope: "write"}, + }, +}) +if err != nil || !res.IsValid { + // unauthorized +} +``` + +**Fetch the principal's granted permissions** -- `GetPermissions` returns the `resource:scope` permissions for the authenticated principal. Pass the auth header (or session cookie) so the principal can be identified. + +```go +permissions, err := authorizerClient.GetPermissions(map[string]string{ + "Authorization": "Bearer your-access-token", +}) +if err != nil { + panic(err) +} +for _, p := range permissions { + fmt.Println(p.Resource, p.Scope) +} +``` + ## Available Methods The SDK provides the following methods: @@ -90,8 +124,9 @@ The SDK provides the following methods: - `GetProfile` -- Get user profile - `UpdateProfile` -- Update user profile - `MagicLinkLogin` -- Login with magic link -- `ValidateJWTToken` -- Validate a JWT token -- `GetSession` -- Get current session +- `ValidateJWTToken` -- Validate a JWT token (optionally with `RequiredPermissions` for FGA) +- `GetSession` -- Get current session (optionally with `RequiredPermissions` for FGA) +- `GetPermissions` -- Get the fine-grained `resource:scope` permissions granted to the authenticated user - `RevokeToken` -- Revoke a token - `Logout` -- Logout user -- `ValidateSession` -- Validate a session +- `ValidateSession` -- Validate a session (optionally with `RequiredPermissions` for FGA) diff --git a/docs/sdks/authorizer-js/functions.md b/docs/sdks/authorizer-js/functions.md index 8ca6a3a..f470b40 100644 --- a/docs/sdks/authorizer-js/functions.md +++ b/docs/sdks/authorizer-js/functions.md @@ -17,6 +17,7 @@ title: Functions - [signup](#--signup) - [verifyEmail](#--verifyemail) - [getProfile](#--getprofile) +- [getPermissions](#--getpermissions) - [updateProfile](#--updateprofile) - [forgotPassword](#--forgotpassword) - [resetPassword](#--resetpassword) @@ -291,6 +292,39 @@ const { data, errors } = await authRef.getProfile({ }) ``` +## - `getPermissions` + +Function to fetch the fine-grained authorization (FGA) permissions granted to the authenticated user. This function makes an authorized request, hence if it is used from the browser the HTTP cookie is sent if user has logged in else you need to pass headers object. + +It accepts the optional JSON object as parameter, you can pass the HTTP Headers there. + +| Key | Description | Required | +| --------------- | -------------------------------------------------------------------------------------- | -------- | +| `Authorization` | Authorization header passed to the server. It needs `Bearer access_token` as its value | true | + +It returns an array of permission objects in the response `data`. Each object has the following keys + +**Response** + +| Key | Description | +| ---------- | ------------------------------------------------------------------- | +| `resource` | The resource the permission applies to, e.g. `documents` | +| `scope` | The action allowed on the resource, e.g. `read`, `write`, `delete` | + +**Sample Usage** + +```js +// from browser if HTTP cookie is present +const { data, errors } = await authRef.getPermissions() + +// from NodeJS / if HTTP cookie is not used +const { data, errors } = await authRef.getPermissions({ + Authorization: `Bearer ${token}`, +}) + +// data => [{ resource: 'documents', scope: 'read' }, ...] +``` + ## - `updateProfile` Function to update profile of user. This function makes an authorized request, hence if it is used from the browser the HTTP cookie is sent if user has logged in else you need to pass headers object. @@ -473,7 +507,7 @@ const { data, errors } await authRef.getMetadata() Function to get session information. This function makes an authorized request, hence if it is used from the browser the HTTP cookie is sent if user has logged in else you need to pass headers object. -It accepts the optional JSON object as parameter, you can pass the HTTP Headers there. Optionally you can also validate the roles against the given token by passing the `roles` as second argument to function. +It accepts the optional JSON object as parameter, you can pass the HTTP Headers there. Optionally you can also pass a `SessionQueryRequest` object as the second argument to validate `roles` and `required_permissions` (FGA) against the session — if any required permission is denied, the request returns unauthorized. | Key | Description | Required | | --------------- | ------------------------------------------------------------------------------------ | -------- | @@ -512,6 +546,16 @@ const { data, errors } = await authRef.getSession( }, 'admin', ) + +// with fine-grained authorization (FGA) checks +const { data, errors } = await authRef.getSession( + { + Authorization: `Bearer some_token`, + }, + { + required_permissions: [{ resource: 'documents', scope: 'read' }], + }, +) ``` ## - `revokeToken` @@ -578,9 +622,10 @@ It expects the JSON object as parameter with following parameters | Key | Description | Required | | ------------ | -------------------------------------------------------------------------------------------------------- | -------- | -| `token_type` | Type of token that needs to be validated. It can be one of `access_token`, `refresh_token` or `id_token` | `true` | -| `token` | Jwt token string | `true` | -| `roles` | Array of roles to validate jwt token for | `false` | +| `token_type` | Type of token that needs to be validated. It can be one of `access_token`, `refresh_token` or `id_token` | `true` | +| `token` | Jwt token string | `true` | +| `roles` | Array of roles to validate jwt token for | `false` | +| `required_permissions` | Array of `{ resource, scope }` permissions (FGA) that must **all** be granted to the principal (AND semantics). If any is denied, `is_valid` is `false` | `false` | It returns the following keys in response `data` object @@ -594,8 +639,18 @@ It returns the following keys in response `data` object ```js const { data, errors } = await authRef.validateJWTToken({ - token_type: `access_token` - token: `some jwt token string` + token_type: `access_token`, + token: `some jwt token string`, +}) + +// with fine-grained authorization (FGA) checks +const { data, errors } = await authRef.validateJWTToken({ + token_type: `access_token`, + token: `some jwt token string`, + required_permissions: [ + { resource: 'documents', scope: 'read' }, + { resource: 'documents', scope: 'write' }, + ], }) ``` @@ -607,8 +662,9 @@ It expects the JSON object as parameter with following parameters | Key | Description | Required | | -------- | --------------------------------------------------------------------------------------------------- | -------- | -| `cookie` | browser session cookie value. If not present it will need coookie present in header as https cookie | `false` | -| `roles` | Array of roles to validate jwt token for | `false` | +| `cookie` | browser session cookie value. If not present it will need coookie present in header as https cookie | `false` | +| `roles` | Array of roles to validate jwt token for | `false` | +| `required_permissions` | Array of `{ resource, scope }` permissions (FGA) that must **all** be granted to the principal (AND semantics). If any is denied, `is_valid` is `false` | `false` | It returns the following keys in response `data` object @@ -624,6 +680,12 @@ It returns the following keys in response `data` object const { data, errors } = await authRef.validateSession({ cookie: ``, }) + +// with fine-grained authorization (FGA) checks +const { data, errors } = await authRef.validateSession({ + cookie: ``, + required_permissions: [{ resource: 'documents', scope: 'read' }], +}) ``` ## - `verifyOtp` From 52317ade16dd5b320f06e26a37d5253e1d6fc842 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Sat, 6 Jun 2026 10:54:30 +0530 Subject: [PATCH 2/2] docs(authorization): note FGA admin mutations are available in the dashboard UI --- docs/core/authorization.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/core/authorization.md b/docs/core/authorization.md index fc259d2..3e54927 100644 --- a/docs/core/authorization.md +++ b/docs/core/authorization.md @@ -102,6 +102,10 @@ Omit `required_permissions` to preserve pre-FGA behavior — the call returns/va All admin mutations require the super-admin secret (cookie or `X-Authorizer-Admin-Secret`). They are prefixed with `_authz_` to namespace the authorization API distinctly from other admin operations. +:::tip +Every mutation in this section can also be performed from the admin UI at **`/dashboard`** (Authorization section) — no GraphQL required. The dashboard calls these same `_authz_` mutations under the hood, so the two are interchangeable. +::: + ### Step 1 — Define resources and scopes ```graphql