@uveysservetoglu/kobil-auth 1.0.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 +37 -0
- package/dist/client.d.ts +24 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +93 -0
- package/dist/client.js.map +1 -0
- package/dist/error.d.ts +5 -0
- package/dist/error.d.ts.map +1 -0
- package/dist/error.js +9 -0
- package/dist/error.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/package.json +28 -0
package/README.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# @uveysservetoglu/kobil-auth
|
|
2
|
+
|
|
3
|
+
KOBIL OIDC (OpenID Connect) authentication helper for Node.js / TypeScript.
|
|
4
|
+
|
|
5
|
+
- Build authorization redirect URLs with a secure random nonce
|
|
6
|
+
- Exchange authorization codes for tokens
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install @uveysservetoglu/kobil-auth
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import { AuthClient } from "@uveysservetoglu/kobil-auth";
|
|
14
|
+
|
|
15
|
+
const auth = new AuthClient({
|
|
16
|
+
authorizationEndpoint: process.env.OAUTH_URL!,
|
|
17
|
+
tokenEndpoint: process.env.OTOKEN_URL!,
|
|
18
|
+
clientId: process.env.OAUTH_CLIENT_ID!,
|
|
19
|
+
clientSecret: process.env.OAUTH_CLIENT_SECRET!,
|
|
20
|
+
scope: "openid profile email",
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// 1. Redirect the user to log in
|
|
24
|
+
const url = auth.buildAuthorizationUrl("https://app.example.com/callback");
|
|
25
|
+
|
|
26
|
+
// 2. On the callback, exchange the code
|
|
27
|
+
const tokens = await auth.exchangeCodeForToken(code, "https://app.example.com/callback");
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
JavaScript usage is identical (`const { AuthClient } = require("@uveysservetoglu/kobil-auth")`).
|
|
31
|
+
|
|
32
|
+
Failures throw `KobilAuthError` (extends `KobilError` from `@uveysservetoglu/kobil-core`), carrying
|
|
33
|
+
`statusCode` and `responseBody` when available.
|
|
34
|
+
|
|
35
|
+
## License
|
|
36
|
+
|
|
37
|
+
MIT
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface AuthClientOptions {
|
|
2
|
+
authorizationEndpoint: string;
|
|
3
|
+
tokenEndpoint: string;
|
|
4
|
+
clientId: string;
|
|
5
|
+
clientSecret: string;
|
|
6
|
+
/** Space-separated scopes. Default: "openid". */
|
|
7
|
+
scope?: string;
|
|
8
|
+
/** OAuth2 response type. Default: "code". */
|
|
9
|
+
responseType?: string;
|
|
10
|
+
/** OAuth2 response mode. Default: "query". */
|
|
11
|
+
responseMode?: string;
|
|
12
|
+
/** Length of the generated nonce. Default: 32. */
|
|
13
|
+
nonceLength?: number;
|
|
14
|
+
}
|
|
15
|
+
/** OIDC authentication helper: build the login redirect URL and exchange the code for tokens. */
|
|
16
|
+
export declare class AuthClient {
|
|
17
|
+
private readonly options;
|
|
18
|
+
constructor(options: AuthClientOptions);
|
|
19
|
+
/** Builds the authorization redirect URL, embedding a fresh secure nonce. */
|
|
20
|
+
buildAuthorizationUrl(redirectUri: string): string;
|
|
21
|
+
/** Exchanges an authorization code for tokens. Returns the parsed token response. */
|
|
22
|
+
exchangeCodeForToken(code: string, redirectUri: string, signal?: AbortSignal): Promise<Record<string, unknown>>;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,iBAAiB;IAChC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8CAA8C;IAC9C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kDAAkD;IAClD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,iGAAiG;AACjG,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8B;gBAE1C,OAAO,EAAE,iBAAiB;IAetC,6EAA6E;IAC7E,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAclD,qFAAqF;IAC/E,oBAAoB,CACxB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAsCpC"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AuthClient = void 0;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
5
|
+
const error_1 = require("./error");
|
|
6
|
+
const NONCE_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_-";
|
|
7
|
+
/** OIDC authentication helper: build the login redirect URL and exchange the code for tokens. */
|
|
8
|
+
class AuthClient {
|
|
9
|
+
options;
|
|
10
|
+
constructor(options) {
|
|
11
|
+
if (!options.authorizationEndpoint)
|
|
12
|
+
throw new error_1.KobilAuthError("authorizationEndpoint is required.");
|
|
13
|
+
if (!options.tokenEndpoint)
|
|
14
|
+
throw new error_1.KobilAuthError("tokenEndpoint is required.");
|
|
15
|
+
if (!options.clientId)
|
|
16
|
+
throw new error_1.KobilAuthError("clientId is required.");
|
|
17
|
+
if (!options.clientSecret)
|
|
18
|
+
throw new error_1.KobilAuthError("clientSecret is required.");
|
|
19
|
+
this.options = {
|
|
20
|
+
scope: "openid",
|
|
21
|
+
responseType: "code",
|
|
22
|
+
responseMode: "query",
|
|
23
|
+
nonceLength: 32,
|
|
24
|
+
...options,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/** Builds the authorization redirect URL, embedding a fresh secure nonce. */
|
|
28
|
+
buildAuthorizationUrl(redirectUri) {
|
|
29
|
+
if (!redirectUri)
|
|
30
|
+
throw new error_1.KobilAuthError("redirectUri cannot be empty.");
|
|
31
|
+
const o = this.options;
|
|
32
|
+
const params = new URLSearchParams({
|
|
33
|
+
client_id: o.clientId,
|
|
34
|
+
redirect_uri: redirectUri,
|
|
35
|
+
scope: o.scope,
|
|
36
|
+
response_type: o.responseType,
|
|
37
|
+
response_mode: o.responseMode,
|
|
38
|
+
nonce: generateNonce(o.nonceLength),
|
|
39
|
+
});
|
|
40
|
+
return `${o.authorizationEndpoint}?${params.toString()}`;
|
|
41
|
+
}
|
|
42
|
+
/** Exchanges an authorization code for tokens. Returns the parsed token response. */
|
|
43
|
+
async exchangeCodeForToken(code, redirectUri, signal) {
|
|
44
|
+
if (!code)
|
|
45
|
+
throw new error_1.KobilAuthError("code cannot be empty.");
|
|
46
|
+
if (!redirectUri)
|
|
47
|
+
throw new error_1.KobilAuthError("redirectUri cannot be empty.");
|
|
48
|
+
const body = new URLSearchParams({
|
|
49
|
+
client_id: this.options.clientId,
|
|
50
|
+
client_secret: this.options.clientSecret,
|
|
51
|
+
code,
|
|
52
|
+
redirect_uri: redirectUri,
|
|
53
|
+
grant_type: "authorization_code",
|
|
54
|
+
});
|
|
55
|
+
let response;
|
|
56
|
+
try {
|
|
57
|
+
response = await fetch(this.options.tokenEndpoint, {
|
|
58
|
+
method: "POST",
|
|
59
|
+
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
60
|
+
body,
|
|
61
|
+
signal,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
catch (cause) {
|
|
65
|
+
throw new error_1.KobilAuthError("An error occurred while exchanging code for token.", { cause });
|
|
66
|
+
}
|
|
67
|
+
const text = await response.text();
|
|
68
|
+
if (!response.ok) {
|
|
69
|
+
throw new error_1.KobilAuthError(`Token endpoint returned ${response.status}.`, {
|
|
70
|
+
statusCode: response.status,
|
|
71
|
+
responseBody: text,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
return JSON.parse(text);
|
|
76
|
+
}
|
|
77
|
+
catch (cause) {
|
|
78
|
+
throw new error_1.KobilAuthError("Token endpoint returned invalid JSON.", { cause, responseBody: text });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
exports.AuthClient = AuthClient;
|
|
83
|
+
function generateNonce(length) {
|
|
84
|
+
if (length <= 0)
|
|
85
|
+
throw new error_1.KobilAuthError("Nonce length must be greater than zero.");
|
|
86
|
+
const bytes = (0, crypto_1.randomBytes)(length);
|
|
87
|
+
let result = "";
|
|
88
|
+
for (let i = 0; i < length; i++) {
|
|
89
|
+
result += NONCE_CHARS[bytes[i] % NONCE_CHARS.length];
|
|
90
|
+
}
|
|
91
|
+
return result;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/error.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAEzD,4DAA4D;AAC5D,qBAAa,cAAe,SAAQ,UAAU;CAAG"}
|
package/dist/error.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.KobilAuthError = void 0;
|
|
4
|
+
const kobil_core_1 = require("@uveysservetoglu/kobil-core");
|
|
5
|
+
/** Thrown when an auth operation (token exchange) fails. */
|
|
6
|
+
class KobilAuthError extends kobil_core_1.KobilError {
|
|
7
|
+
}
|
|
8
|
+
exports.KobilAuthError = KobilAuthError;
|
|
9
|
+
//# sourceMappingURL=error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.js","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":";;;AAAA,4DAAyD;AAEzD,4DAA4D;AAC5D,MAAa,cAAe,SAAQ,uBAAU;CAAG;AAAjD,wCAAiD"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,YAAY,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.KobilAuthError = exports.AuthClient = void 0;
|
|
4
|
+
var client_1 = require("./client");
|
|
5
|
+
Object.defineProperty(exports, "AuthClient", { enumerable: true, get: function () { return client_1.AuthClient; } });
|
|
6
|
+
var error_1 = require("./error");
|
|
7
|
+
Object.defineProperty(exports, "KobilAuthError", { enumerable: true, get: function () { return error_1.KobilAuthError; } });
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,mCAAsC;AAA7B,oGAAA,UAAU,OAAA;AAEnB,iCAAyC;AAAhC,uGAAA,cAAc,OAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@uveysservetoglu/kobil-auth",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "KOBIL OIDC (OpenID Connect) authentication helper for Node.js: build authorization URLs and exchange authorization codes for tokens.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"keywords": [
|
|
12
|
+
"kobil",
|
|
13
|
+
"oidc",
|
|
14
|
+
"oauth2",
|
|
15
|
+
"authentication",
|
|
16
|
+
"openid-connect"
|
|
17
|
+
],
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/uveysservetoglu/kobil-sdks"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@uveysservetoglu/kobil-core": "^1.0.0"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc -b"
|
|
27
|
+
}
|
|
28
|
+
}
|