@tensorgrad/oauth 0.1.0 → 0.2.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 +21 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4 -0
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -7,6 +7,7 @@ Small OAuth client SDK for integrating tensorGrad SSO into first-party apps.
|
|
|
7
7
|
- creates `state` values
|
|
8
8
|
- creates PKCE verifier/challenge pairs
|
|
9
9
|
- builds tensorGrad `/oauth/authorize` URLs
|
|
10
|
+
- supports `prompt=login` for account switching
|
|
10
11
|
- exchanges authorization codes at `/oauth/token`
|
|
11
12
|
- fetches canonical identity from `/oauth/userinfo`
|
|
12
13
|
- normalizes tensorGrad user payloads
|
|
@@ -45,6 +46,7 @@ console.log(TENSORGRAD_ISSUER);
|
|
|
45
46
|
|
|
46
47
|
```ts
|
|
47
48
|
import {
|
|
49
|
+
DEFAULT_TG_SCOPES,
|
|
48
50
|
TENSORGRAD_ISSUER,
|
|
49
51
|
assertGrantedScopes,
|
|
50
52
|
createAuthorizationUrl,
|
|
@@ -84,7 +86,7 @@ export default {
|
|
|
84
86
|
},
|
|
85
87
|
{
|
|
86
88
|
redirectUri,
|
|
87
|
-
scope:
|
|
89
|
+
scope: DEFAULT_TG_SCOPES,
|
|
88
90
|
state,
|
|
89
91
|
codeChallenge: pkce.codeChallenge,
|
|
90
92
|
codeChallengeMethod: pkce.codeChallengeMethod
|
|
@@ -99,9 +101,21 @@ export default {
|
|
|
99
101
|
}
|
|
100
102
|
|
|
101
103
|
if (url.pathname === "/auth/callback") {
|
|
104
|
+
const oauthError = url.searchParams.get("error");
|
|
105
|
+
const oauthErrorDescription = url.searchParams.get("error_description");
|
|
102
106
|
const code = url.searchParams.get("code");
|
|
103
107
|
const state = url.searchParams.get("state");
|
|
104
108
|
|
|
109
|
+
if (oauthError) {
|
|
110
|
+
return Response.json(
|
|
111
|
+
{
|
|
112
|
+
error: oauthError,
|
|
113
|
+
errorDescription: oauthErrorDescription ?? null
|
|
114
|
+
},
|
|
115
|
+
{ status: 400 }
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
105
119
|
if (!code || !state) {
|
|
106
120
|
return new Response("Missing code or state", { status: 400 });
|
|
107
121
|
}
|
|
@@ -112,6 +126,7 @@ export default {
|
|
|
112
126
|
const expectedState = "<persisted-state>";
|
|
113
127
|
const codeVerifier = "<persisted-code-verifier>";
|
|
114
128
|
|
|
129
|
+
// Use a constant-time comparison in your app when comparing secrets.
|
|
115
130
|
if (state !== expectedState) {
|
|
116
131
|
return new Response("Invalid state", { status: 400 });
|
|
117
132
|
}
|
|
@@ -125,7 +140,7 @@ export default {
|
|
|
125
140
|
codeVerifier
|
|
126
141
|
});
|
|
127
142
|
|
|
128
|
-
assertGrantedScopes(token.scope,
|
|
143
|
+
assertGrantedScopes(token.scope, DEFAULT_TG_SCOPES);
|
|
129
144
|
|
|
130
145
|
const userFromToken = normalizeTgUser(token.user);
|
|
131
146
|
const userFromUserInfo = normalizeTgUser(
|
|
@@ -149,6 +164,10 @@ export default {
|
|
|
149
164
|
|
|
150
165
|
- `openid` is mandatory and the library enforces that when building authorize URLs.
|
|
151
166
|
- tensorGrad currently uses `https://www.tensorgrad.com` as the OAuth provider.
|
|
167
|
+
- `DEFAULT_TG_SCOPES` is the recommended scope set for first-party apps.
|
|
152
168
|
- `assertGrantedScopes(token.scope, ["admin"])` is the simplest way to require admin access.
|
|
169
|
+
- pass `prompt: "login"` to `createAuthorizationUrl(...)` when you need tensorGrad to force a fresh account selection.
|
|
170
|
+
- handle `error` / `error_description` on the callback before validating `code`
|
|
171
|
+
- compare persisted `state` values using a constant-time comparison in your app
|
|
153
172
|
- `isAdminScopeGranted(token.scope)` is available when you only need a boolean check.
|
|
154
173
|
- app session and logout handling stay in the consuming app.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export declare const TENSORGRAD_ISSUER = "https://www.tensorgrad.com";
|
|
2
|
+
export declare const DEFAULT_TG_SCOPES: readonly ["openid", "profile", "email"];
|
|
2
3
|
export interface tgOAuthConfig {
|
|
3
4
|
issuer: string;
|
|
4
5
|
clientId: string;
|
|
@@ -13,6 +14,7 @@ export interface AuthorizationUrlOptions {
|
|
|
13
14
|
redirectUri: string;
|
|
14
15
|
scope: string[] | string;
|
|
15
16
|
state: string;
|
|
17
|
+
prompt?: "login";
|
|
16
18
|
codeChallenge?: string;
|
|
17
19
|
codeChallengeMethod?: "S256" | "plain";
|
|
18
20
|
extraParams?: Record<string, string>;
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export const TENSORGRAD_ISSUER = "https://www.tensorgrad.com";
|
|
2
|
+
export const DEFAULT_TG_SCOPES = ["openid", "profile", "email"];
|
|
2
3
|
const MIN_STATE_BYTES = 16;
|
|
3
4
|
const MAX_RANDOM_BYTES = 96;
|
|
4
5
|
const MIN_PKCE_RANDOM_BYTES = 32;
|
|
@@ -89,6 +90,9 @@ export function createAuthorizationUrl(config, options) {
|
|
|
89
90
|
url.searchParams.set("response_type", "code");
|
|
90
91
|
url.searchParams.set("scope", scope);
|
|
91
92
|
url.searchParams.set("state", state);
|
|
93
|
+
if (options.prompt) {
|
|
94
|
+
url.searchParams.set("prompt", options.prompt);
|
|
95
|
+
}
|
|
92
96
|
if (options.codeChallenge) {
|
|
93
97
|
url.searchParams.set("code_challenge", requireNonEmptyString("codeChallenge", options.codeChallenge));
|
|
94
98
|
url.searchParams.set("code_challenge_method", options.codeChallengeMethod ?? "S256");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tensorgrad/oauth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Small OAuth client SDK for tensorGrad SSO integrations.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -27,6 +27,10 @@
|
|
|
27
27
|
"tensorgrad",
|
|
28
28
|
"sso"
|
|
29
29
|
],
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/tensorGrad/tgAuth"
|
|
33
|
+
},
|
|
30
34
|
"license": "MIT",
|
|
31
35
|
"devDependencies": {
|
|
32
36
|
"typescript": "^5.9.2"
|