Skip to content

Commit 8f4df9d

Browse files
committed
docs: update README for v2.0.0
1 parent dc16e71 commit 8f4df9d

1 file changed

Lines changed: 104 additions & 119 deletions

File tree

README.md

Lines changed: 104 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,95 @@
11
# authorizer-go
22

3-
Golang SDK for [authorizer.dev](https://authorizer.dev) server. This SDK will be handy to add API middleware where you can authorize your users. It will also empower you to perform various auth operations on authorizer server.
3+
Go SDK for [authorizer.dev](https://authorizer.dev) — self-hosted authentication & authorization. Current version: **2.0.0**.
44

5-
For detailed explanation of each functions check official [docs](https://pkg.go.dev/github.com/authorizerdev/authorizer-go)
5+
Use this SDK to add auth middleware to your Go services and to call any Authorizer API method. For full API docs see [pkg.go.dev/github.com/authorizerdev/authorizer-go](https://pkg.go.dev/github.com/authorizerdev/authorizer-go).
66

77
## Getting Started
88

9-
**Pre-requisite**: You will need an authorizer instance up and running. Checkout how you can host your instance in the [docs](https://docs.authorizer.dev/deployment)
9+
**Pre-requisite:** A running Authorizer instance. See the [deployment guide](https://docs.authorizer.dev/deployment).
1010

11-
Follow the steps here to install authorizer-go in your golang project and use the methods of SDK to protect/authorize your APIs
11+
Once deployed, get your `Client ID` from the Authorizer dashboard.
1212

13-
Once you have deployed authorizer instance. Get `Client ID` from your authorizer instance dashboard
14-
15-
![client_id](https://res.cloudinary.com/dcfpom7fo/image/upload/v1663437088/Authorizer/client_id_ptjsvc.png)
16-
17-
### Step 1: Install authorizer-go SDK
18-
19-
Run the following command to download authorizer-go SDK
13+
### Step 1: Install the SDK
2014

2115
```bash
2216
go get github.com/authorizerdev/authorizer-go
2317
```
2418

25-
### Step 2: Initialize authorizer client
19+
### Step 2: Initialize the client
2620

2721
**Parameters**
2822

29-
| Key | Type | Required | Description |
30-
| --------------- | ------------------- | -------------------- | --------------------------------------------------------------------------------------------------------------- |
31-
| `clientID` | `string` | `true` | Your unique client identifier obtained from authorizer dashboard |
32-
| `authorizerURL` | `string` | `true` | Authorizer server URL |
33-
| `redirectURL` | `string` | `false` | Default URL to which you would like to redirect the user in case of successful signup / login / forgot password |
34-
| `extraHeaders` | `map[string]string` | `false` | set of headers that you would like to pass with each request |
23+
| Key | Type | Required | Description |
24+
| --------------- | ------------------- | -------- | ---------------------------------------------------------------------------------------------------- |
25+
| `clientID` | `string` | Yes | Client ID from the Authorizer dashboard |
26+
| `authorizerURL` | `string` | Yes | Base URL of your Authorizer instance |
27+
| `redirectURL` | `string` | No | Default redirect URL for signup / login / forgot-password flows |
28+
| `extraHeaders` | `map[string]string` | No | Headers sent on every request (e.g. `Origin`) |
3529

3630
**Example**
3731

3832
```go
39-
defaultHeaders := map[string]string{}
33+
package main
4034

41-
authorizerClient, err := authorizer.NewAuthorizerClient("YOUR_CLIENT_ID", "YOUR_AUHTORIZER_URL", "OPTIONAL_REDIRECT_URL", defaultHeaders)
42-
if err != nil {
43-
panic(err)
35+
import (
36+
authorizer "github.com/authorizerdev/authorizer-go"
37+
)
38+
39+
func main() {
40+
client, err := authorizer.NewAuthorizerClient(
41+
"YOUR_CLIENT_ID",
42+
"https://your-instance.example.com",
43+
"https://your-app.example.com", // optional redirect URL
44+
map[string]string{},
45+
)
46+
if err != nil {
47+
panic(err)
48+
}
49+
_ = client
4450
}
4551
```
4652

47-
> **Note (Authorizer ≥ v2.3.0):** the server's CSRF guard requires an `Origin`
48-
> header on state-changing requests. The client sends the Authorizer server's
49-
> own origin by default, which always passes. If your instance restricts
50-
> `ALLOWED_ORIGINS`, pass your app's origin instead via `extraHeaders`:
51-
> `map[string]string{"Origin": "https://your-app.com"}`.
53+
> **Note (Authorizer >= v2.3.0):** the server's CSRF guard requires an `Origin` header on state-changing requests. The client sends the Authorizer server's own origin by default, which always passes. If your instance restricts `ALLOWED_ORIGINS`, pass your app's origin instead via `extraHeaders`: `map[string]string{"Origin": "https://your-app.com"}`.
5254
53-
### Step 3: Access all the SDK methods using authorizer client instance, initialized on step 2
54-
55-
**Example**
55+
### Step 3: Use the SDK
5656

5757
```go
58-
response, err := authorizerClient.Login(&authorizer.LoginInput{
59-
Email: "test@yopmail.com",
58+
response, err := client.Login(&authorizer.LoginInput{
59+
Email: "user@example.com",
6060
Password: "Abc@123",
6161
})
6262
if err != nil {
6363
panic(err)
6464
}
65+
fmt.Println("access_token:", response.AccessToken)
6566
```
6667

68+
## Admin API
69+
70+
The SDK exposes admin methods for server-side user management. Admin operations require the admin secret; supply it via `extraHeaders`:
71+
72+
```go
73+
adminClient, err := authorizer.NewAuthorizerClient(
74+
"YOUR_CLIENT_ID",
75+
"https://your-instance.example.com",
76+
"",
77+
map[string]string{"x-authorizer-admin-secret": "YOUR_ADMIN_SECRET"},
78+
)
79+
```
80+
81+
See [admin_methods.go](admin_methods.go) for the full list of available admin operations.
82+
6783
## Fine-grained authorization (FGA)
6884

69-
Authorizer ships an embedded [OpenFGA](https://openfga.dev) engine for relationship-based
70-
access control (ReBAC). You model your domain as object **types** with **relations**
71-
(`viewer`, `editor`, `owner`…), grant access by writing **relationship tuples**
72-
(`user:alice` is `viewer` of `document:1`), and ask the engine whether access is allowed.
73-
74-
Authoring the model and tuples is an admin task — do it once in the dashboard under
75-
**Authorization**, or via the `_fga_*` admin GraphQL API. The SDK exposes only the
76-
read-side checks an application needs at request time. For every call the subject
77-
defaults to the authenticated caller and is pinned server-side from the request
78-
headers (bearer token / session cookie), so pass them. The optional `User` field
79-
(`"type:id"`, or a bare id treated as `"user:<id>"`) overrides the subject, but is
80-
honored only when the caller is a super-admin or it equals the caller's own token
81-
subject — anything else is rejected by the server.
82-
83-
**1. Check permissions**`CheckPermissions` evaluates one or more
84-
"does the caller have `relation` on `object`?" checks in a single round trip.
85-
Each result echoes its relation/object pair and comes back in the same order as
86-
the supplied checks.
85+
Authorizer ships an embedded [OpenFGA](https://openfga.dev) engine for relationship-based access control (ReBAC). You model your domain as object **types** with **relations** (`viewer`, `editor`, `owner`…), grant access by writing **relationship tuples**, and ask the engine whether access is allowed.
86+
87+
Authoring the model and tuples is an admin task — do it once in the dashboard under **Authorization**, or via the `_fga_*` admin GraphQL API. The SDK exposes only the read-side checks an application needs at request time. The subject defaults to the authenticated caller and is pinned server-side from the request headers. The optional `User` field overrides the subject but is honored only for super-admins or when it equals the caller's own token subject.
88+
89+
**Check permissions** — evaluates one or more relation checks in a single round trip:
8790

8891
```go
89-
res, err := authorizerClient.CheckPermissions(&authorizer.CheckPermissionsRequest{
92+
res, err := client.CheckPermissions(&authorizer.CheckPermissionsRequest{
9093
Checks: []*authorizer.PermissionCheckInput{
9194
{Relation: "can_view", Object: "document:1"},
9295
{Relation: "can_edit", Object: "document:1"},
@@ -102,14 +105,10 @@ for _, r := range res.Results {
102105
}
103106
```
104107

105-
**2. List accessible objects**`ListPermissions` returns the ids of every object of a
106-
type the caller holds a relation on (handy for filtering a list to what the user can see).
107-
Both filters are optional: an empty request enumerates everything the caller holds, with
108-
the `(Object, Relation)` detail in `Permissions` and `Truncated` set when the result was
109-
capped at 1000 entries.
108+
**List accessible objects** — returns the ids of every object of a type the caller holds a relation on:
110109

111110
```go
112-
res, err := authorizerClient.ListPermissions(&authorizer.ListPermissionsRequest{
111+
res, err := client.ListPermissions(&authorizer.ListPermissionsRequest{
113112
Relation: "can_view",
114113
ObjectType: "document",
115114
}, map[string]string{"Authorization": "Bearer " + token})
@@ -119,85 +118,71 @@ if err != nil {
119118
fmt.Println(res.Objects) // ["document:1", "document:7", ...]
120119
```
121120

122-
## How to use authorizer as API gateway
123-
124-
> Note: This example demonstrates how to use authorizer in middleware for a [go-gin](https://github.com/gin-gonic/gin) server. But logic remains the same under the hood, where you can get auth token from `header` and validate it via authorizer SDK
121+
## API gateway example (gin)
125122

126123
```go
127124
package main
128125

129126
import (
130-
"net/http"
131-
"strings"
127+
"net/http"
128+
"strings"
132129

133-
"github.com/authorizerdev/authorizer-go"
134-
"github.com/gin-gonic/gin"
130+
authorizer "github.com/authorizerdev/authorizer-go"
131+
"github.com/gin-gonic/gin"
135132
)
136133

137134
func AuthorizeMiddleware() gin.HandlerFunc {
138-
return func(c *gin.Context) {
139-
/**
140-
for open routes you can add condition here and just return with c.Next()
141-
so that it does not validate token for those routes
142-
*/
143-
144-
authHeader := c.Request.Header.Get("Authorization")
145-
tokenSplit := strings.Split(authHeader, " ")
146-
147-
defaultHeaders := map[string]string{}
148-
authorizerClient, err := authorizer.NewAuthorizerClient("YOUR_CLIENT_ID", "YOUR_AUHTORIZER_URL", "OPTIONAL_REDIRECT_URL", defaultHeaders)
149-
if err != nil {
150-
// unauthorized
151-
c.AbortWithStatusJSON(401, "unauthorized")
152-
return
153-
}
154-
155-
if len(tokenSplit) < 2 || tokenSplit[1] == "" {
156-
// unauthorized
157-
c.AbortWithStatusJSON(401, "unauthorized")
158-
return
159-
}
160-
161-
res, err := authorizerClient.ValidateJWTToken(&authorizer.ValidateJWTTokenInput{
162-
TokenType: authorizer.TokenTypeIDToken,
163-
Token: tokenSplit[1],
164-
})
165-
if err != nil {
166-
// unauthorized
167-
c.AbortWithStatusJSON(401, "unauthorized")
168-
return
169-
}
170-
171-
if !res.IsValid {
172-
// unauthorized
173-
c.AbortWithStatusJSON(401, "unauthorized")
174-
return
175-
}
176-
177-
c.Next()
178-
}
135+
return func(c *gin.Context) {
136+
authHeader := c.Request.Header.Get("Authorization")
137+
tokenSplit := strings.Split(authHeader, " ")
138+
139+
client, err := authorizer.NewAuthorizerClient(
140+
"YOUR_CLIENT_ID",
141+
"YOUR_AUTHORIZER_URL",
142+
"",
143+
map[string]string{},
144+
)
145+
if err != nil || len(tokenSplit) < 2 || tokenSplit[1] == "" {
146+
c.AbortWithStatusJSON(401, "unauthorized")
147+
return
148+
}
149+
150+
res, err := client.ValidateJWTToken(&authorizer.ValidateJWTTokenInput{
151+
TokenType: authorizer.TokenTypeIDToken,
152+
Token: tokenSplit[1],
153+
})
154+
if err != nil || !res.IsValid {
155+
c.AbortWithStatusJSON(401, "unauthorized")
156+
return
157+
}
158+
159+
c.Next()
160+
}
179161
}
180162

181163
func main() {
182-
router := gin.New()
183-
router.Use(AuthorizeMiddleware())
164+
router := gin.New()
165+
router.Use(AuthorizeMiddleware())
184166

185-
router.GET("/ping", func(c *gin.Context) {
186-
c.JSON(http.StatusOK, gin.H{
187-
"message": "pong",
188-
})
189-
})
167+
router.GET("/ping", func(c *gin.Context) {
168+
c.JSON(http.StatusOK, gin.H{"message": "pong"})
169+
})
190170

191-
router.Run(":8090")
171+
router.Run(":8090")
192172
}
193173
```
194174

175+
Test the protected endpoint:
176+
177+
```bash
178+
curl -H 'Authorization: Bearer JWT_TOKEN' http://localhost:8090/ping
179+
```
180+
181+
---
195182

196-
**CURL command to test go-gin server created in example**
183+
## Release
197184

198-
Copy JWT ID token from login response of authorizer `login` mutation / social media login and replace `JWT_TOKEN` below
185+
1. Tag the commit: `git tag v<version>`
186+
2. Push with tags: `git push origin main --tags`
199187

200-
```bash
201-
curl --location --request GET 'http://localhost:8090/ping' \
202-
--header 'Authorization: Bearer JWT_TOKEN'
203-
```
188+
The GitHub Actions release workflow handles the GitHub Release creation automatically. Go modules are versioned by tags — no additional publish step is needed.

0 commit comments

Comments
 (0)