@gjermundgaraba/clankerauth-sdk 0.7.2 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -9
- package/dist/resource.d.ts +1 -1
- package/dist/session.d.ts +1 -1
- package/dist/verify.js +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @gjermundgaraba/clankerauth-sdk
|
|
2
2
|
|
|
3
|
-
Effect-native [
|
|
3
|
+
Effect-native [clankerauth](https://github.com/gjermundgaraba/clankerauth) verification. Verifies JWT access tokens and API keys, including the tokens a reverse proxy obtains through the issuer's forward auth for browser sessions. Optional **effect-actions** integration provides request-scoped identity, OAuth discovery, scope enforcement and a `session` contract a browser page can import on its own.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -11,7 +11,13 @@ vp add @gjermundgaraba/clankerauth-sdk
|
|
|
11
11
|
Install Effect in the application:
|
|
12
12
|
|
|
13
13
|
```sh
|
|
14
|
-
vp add effect@4.0.0-rc.
|
|
14
|
+
vp add effect@4.0.0-rc.117
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The `/session` and `/effect-actions` entry points also need effect-actions 0.7 (the SDK's declarations are built against it):
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
vp add @gjermundgaraba/effect-actions@0.7.0
|
|
15
21
|
```
|
|
16
22
|
|
|
17
23
|
## Entry points
|
|
@@ -35,7 +41,7 @@ import { FetchHttpClient } from "effect/unstable/http";
|
|
|
35
41
|
import { Verifier } from "@gjermundgaraba/clankerauth-sdk";
|
|
36
42
|
|
|
37
43
|
const makeVerifier = Verifier.make({
|
|
38
|
-
issuer: "https://
|
|
44
|
+
issuer: "https://clankerauth.internal/api/auth",
|
|
39
45
|
resource: "https://notes.internal/",
|
|
40
46
|
requiredScopes: ["notes:read"],
|
|
41
47
|
}).pipe(Effect.provide(FetchHttpClient.layer));
|
|
@@ -44,7 +50,7 @@ const makeVerifier = Verifier.make({
|
|
|
44
50
|
|
|
45
51
|
## One resource per application
|
|
46
52
|
|
|
47
|
-
Register **one** resource in the
|
|
53
|
+
Register **one** resource in the clankerauth dashboard, identified by the application's public origin root, written with its trailing slash: `https://notes.internal/`. That one resource covers `/api`, `/mcp` and any socket, with one RFC 9728 document at `/.well-known/oauth-protected-resource` and one `forward_auth` block in the proxy.
|
|
48
54
|
|
|
49
55
|
`Resource.make` takes the public URL and derives that identifier itself, so the application never writes it twice and never writes a form an MCP client would rewrite. Any path on the URL is discarded. The official client's own `checkResourceAllowed` accepts an origin-root resource for an endpoint beneath it.
|
|
50
56
|
|
|
@@ -53,7 +59,6 @@ Acquire the resource once at application construction, never per request.
|
|
|
53
59
|
```ts
|
|
54
60
|
import { Effect, Layer } from "effect";
|
|
55
61
|
import { FetchHttpClient } from "effect/unstable/http";
|
|
56
|
-
import { McpProtocol } from "effect/unstable/ai";
|
|
57
62
|
import { Resource } from "@gjermundgaraba/clankerauth-sdk/effect-actions";
|
|
58
63
|
import { authenticationErrors } from "@gjermundgaraba/clankerauth-sdk/errors";
|
|
59
64
|
import * as ActionMcp from "@gjermundgaraba/effect-actions/ActionMcp";
|
|
@@ -62,7 +67,7 @@ import * as ActionMcp from "@gjermundgaraba/effect-actions/ActionMcp";
|
|
|
62
67
|
const routes = Layer.unwrap(
|
|
63
68
|
Effect.gen(function* () {
|
|
64
69
|
const notes = yield* Resource.make({
|
|
65
|
-
issuer: "https://
|
|
70
|
+
issuer: "https://clankerauth.internal/api/auth",
|
|
66
71
|
publicUrl: new URL("https://notes.internal"),
|
|
67
72
|
scopes: { read: "notes:read", write: "notes:write" },
|
|
68
73
|
});
|
|
@@ -76,7 +81,6 @@ const routes = Layer.unwrap(
|
|
|
76
81
|
name: "notes",
|
|
77
82
|
version: "1.0.0",
|
|
78
83
|
path: "/mcp",
|
|
79
|
-
protocols: [McpProtocol.v2026_07_28],
|
|
80
84
|
errors: authenticationErrors,
|
|
81
85
|
before: notes.authorize,
|
|
82
86
|
}).pipe(Layer.provide(Resource.middleware(notes).layer)),
|
|
@@ -85,7 +89,7 @@ const routes = Layer.unwrap(
|
|
|
85
89
|
).pipe(Layer.provide(FetchHttpClient.layer));
|
|
86
90
|
```
|
|
87
91
|
|
|
88
|
-
Serve this layer with Effect's `HttpRouter` and your Node server layer. If using `@effect/platform-node`, install the matching `@effect/platform-node@4.0.0-rc.
|
|
92
|
+
Serve this layer with Effect's `HttpRouter` and your Node server layer. If using `@effect/platform-node`, install the matching `@effect/platform-node@4.0.0-rc.117` package. Discovery is public; do not wrap it in authentication. Discovery cache policy belongs to the host. Every authentication response carries `Cache-Control: no-store`.
|
|
89
93
|
|
|
90
94
|
The supplied `HttpClient` must not retry credential exchanges or follow redirects. The SDK overrides only FetchHttpClient's redirect policy to reject redirects, preserves other caller-provided fetch defaults, and never installs retry middleware.
|
|
91
95
|
|
|
@@ -174,7 +178,7 @@ Both checks are raw string comparisons on the headers as sent. Nothing is parsed
|
|
|
174
178
|
|
|
175
179
|
## Browser applications
|
|
176
180
|
|
|
177
|
-
A browser page holds no credential of its own: put it behind a reverse proxy with the issuer's forward auth, described in the
|
|
181
|
+
A browser page holds no credential of its own: put it behind a reverse proxy with the issuer's forward auth, described in the clankerauth README, and the proxy adds the `Authorization` header this package verifies. What the page does need is who it is signed in as, and a way out:
|
|
178
182
|
|
|
179
183
|
```ts
|
|
180
184
|
import { Principal, Session, signOutUrl } from "@gjermundgaraba/clankerauth-sdk/session";
|
package/dist/resource.d.ts
CHANGED
|
@@ -58,7 +58,7 @@ export declare const make: (options: Options) => Effect.Effect<{
|
|
|
58
58
|
readonly subject: Schema.NonEmptyString;
|
|
59
59
|
readonly issuer: Schema.NonEmptyString;
|
|
60
60
|
readonly scopes: Schema.$Array<Schema.String>;
|
|
61
|
-
}>, readonly [], "read",
|
|
61
|
+
}>, readonly [], "read", false>], never>, {
|
|
62
62
|
whoami: () => Effect.Effect<{
|
|
63
63
|
subject: string;
|
|
64
64
|
issuer: string;
|
package/dist/session.d.ts
CHANGED
|
@@ -21,7 +21,7 @@ export declare const Session: ActionGroup.Group<"session", readonly [Action.Acti
|
|
|
21
21
|
readonly subject: Schema.NonEmptyString;
|
|
22
22
|
readonly issuer: Schema.NonEmptyString;
|
|
23
23
|
readonly scopes: Schema.$Array<Schema.String>;
|
|
24
|
-
}>, readonly [], "read",
|
|
24
|
+
}>, readonly [], "read", false>], never>;
|
|
25
25
|
/**
|
|
26
26
|
* Sign out at the issuer, which ends its session and every app's forward cookie, then
|
|
27
27
|
* return to `returnTo`. It is a plain link: any page under the cookie domain may use it.
|
package/dist/verify.js
CHANGED
|
@@ -138,7 +138,7 @@ export const make = Effect.fn("Verifier.make")(function* (options) {
|
|
|
138
138
|
};
|
|
139
139
|
}, Effect.scoped);
|
|
140
140
|
const verifyToken = Effect.fn("Verifier.verifyToken")(function* (token) {
|
|
141
|
-
const principal = yield* token.startsWith("
|
|
141
|
+
const principal = yield* token.startsWith("clankerauth_")
|
|
142
142
|
? options.apiKeys === false
|
|
143
143
|
? Effect.fail(unauthorized())
|
|
144
144
|
: verifyKey(token)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjermundgaraba/clankerauth-sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Effect-native
|
|
3
|
+
"version": "0.9.0",
|
|
4
|
+
"description": "Effect-native clankerauth access-token and API-key verification, with optional effect-actions integration",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -35,11 +35,11 @@
|
|
|
35
35
|
"access": "public"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"effect": "4.0.0-rc.
|
|
38
|
+
"effect": "4.0.0-rc.117",
|
|
39
39
|
"jose": "6.2.12"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@gjermundgaraba/effect-actions": "0.
|
|
42
|
+
"@gjermundgaraba/effect-actions": "0.7.0",
|
|
43
43
|
"@modelcontextprotocol/client": "2.0.0",
|
|
44
44
|
"@types/node": "26.6.2",
|
|
45
45
|
"typescript": "7.0.2",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"vite-plus": "0.3.3"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"@gjermundgaraba/effect-actions": "0.
|
|
50
|
+
"@gjermundgaraba/effect-actions": "^0.7.0"
|
|
51
51
|
},
|
|
52
52
|
"peerDependenciesMeta": {
|
|
53
53
|
"@gjermundgaraba/effect-actions": {
|