coyotte508 HF staff commited on
Commit
a6cffb6
·
verified ·
1 Parent(s): 2e6f129

Update index.js

Browse files
Files changed (1) hide show
  1. index.js +2 -214
index.js CHANGED
@@ -1,215 +1,3 @@
1
- const HUB_URL = "https://huggingface.co";
2
 
3
- async function createApiError(res) {
4
- throw new Error (await res.text());
5
- }
6
-
7
- function hexFromBytes(arr) {
8
- if (globalThis.Buffer) {
9
- return globalThis.Buffer.from(arr).toString("hex");
10
- } else {
11
- const bin = [];
12
- arr.forEach((byte) => {
13
- bin.push(byte.toString(16).padStart(2, "0"));
14
- });
15
- return bin.join("");
16
- }
17
- }
18
-
19
- function base64FromBytes(arr) {
20
- if (globalThis.Buffer) {
21
- return globalThis.Buffer.from(arr).toString("base64");
22
- } else {
23
- const bin = [];
24
- arr.forEach((byte) => {
25
- bin.push(String.fromCharCode(byte));
26
- });
27
- return globalThis.btoa(bin.join(""));
28
- }
29
- }
30
-
31
-
32
-
33
- /**
34
- * Use "Sign in with Hub" to authenticate a user, and get oauth user info / access token.
35
- *
36
- * When called the first time, it will redirect the user to the Hub login page, which then redirects
37
- * to the current URL (or custom URL set).
38
- *
39
- * When called the second time, after the redirect, it will check the query parameters and return
40
- * the oauth user info / access token.
41
- *
42
- * If called inside an iframe, it will open a new window instead of redirecting the iframe, by default.
43
- *
44
- * When called from inside a static Space with OAuth enabled, it will load the config from the space.
45
- *
46
- * (Theoretically, this function could be used to authenticate a user for any OAuth provider supporting PKCE and OpenID Connect by changing `hubUrl`,
47
- * but it is currently only tested with the Hugging Face Hub.)
48
- */
49
- async function oauthLogin(opts) {
50
- if (typeof window === "undefined") {
51
- throw new Error("oauthLogin is only available in the browser");
52
- }
53
-
54
- console.log("localstorage before", JSON.parse(JSON.stringify(localStorage)));
55
-
56
- const hubUrl = opts?.hubUrl || HUB_URL;
57
- const openidConfigUrl = `${new URL(hubUrl).origin}/.well-known/openid-configuration`;
58
- const openidConfigRes = await fetch(openidConfigUrl, {
59
- headers: {
60
- Accept: "application/json",
61
- },
62
- });
63
-
64
- if (!openidConfigRes.ok) {
65
- throw await createApiError(openidConfigRes);
66
- }
67
-
68
- const opendidConfig = await openidConfigRes.json();
69
-
70
- const searchParams = new URLSearchParams(window.location.search);
71
-
72
- const [error, errorDescription] = [searchParams.get("error"), searchParams.get("error_description")];
73
-
74
- if (error) {
75
- throw new Error(`${error}: ${errorDescription}`);
76
- }
77
-
78
- const code = searchParams.get("code");
79
- const nonce = localStorage.getItem("huggingface.co:oauth:nonce");
80
-
81
- if (code && !nonce) {
82
- console.warn("Missing oauth nonce from localStorage");
83
- }
84
-
85
- if (code && nonce) {
86
- const codeVerifier = localStorage.getItem("huggingface.co:oauth:code_verifier");
87
-
88
- if (!codeVerifier) {
89
- throw new Error("Missing oauth code_verifier from localStorage");
90
- }
91
-
92
- const state = searchParams.get("state");
93
-
94
- if (!state) {
95
- throw new Error("Missing oauth state from query parameters in redirected URL");
96
- }
97
-
98
- let parsedState;
99
-
100
- try {
101
- parsedState = JSON.parse(state);
102
- } catch {
103
- throw new Error("Invalid oauth state in redirected URL, unable to parse JSON: " + state);
104
- }
105
-
106
- if (parsedState.nonce !== nonce) {
107
- throw new Error("Invalid oauth state in redirected URL");
108
- }
109
-
110
- console.log("codeVerifier", codeVerifier)
111
-
112
- const tokenRes = await fetch(opendidConfig.token_endpoint, {
113
- method: "POST",
114
- headers: {
115
- "Content-Type": "application/x-www-form-urlencoded",
116
- },
117
- body: new URLSearchParams({
118
- grant_type: "authorization_code",
119
- code,
120
- redirect_uri: parsedState.redirectUri,
121
- code_verifier: codeVerifier,
122
- }).toString(),
123
- });
124
-
125
- localStorage.removeItem("huggingface.co:oauth:code_verifier");
126
- localStorage.removeItem("huggingface.co:oauth:nonce");
127
-
128
- if (!tokenRes.ok) {
129
- throw await createApiError(tokenRes);
130
- }
131
-
132
- const token = await tokenRes.json();
133
-
134
- const accessTokenExpiresAt = new Date(Date.now() + token.expires_in * 1000);
135
-
136
- const userInfoRes = await fetch(opendidConfig.userinfo_endpoint, {
137
- headers: {
138
- Authorization: `Bearer ${token.access_token}`,
139
- },
140
- });
141
-
142
- if (!userInfoRes.ok) {
143
- throw await createApiError(userInfoRes);
144
- }
145
-
146
- const userInfo = await userInfoRes.json();
147
-
148
- return {
149
- accessToken: token.access_token,
150
- accessTokenExpiresAt,
151
- userInfo: {
152
- id: userInfo.sub,
153
- name: userInfo.name,
154
- fullname: userInfo.preferred_username,
155
- email: userInfo.email,
156
- emailVerified: userInfo.email_verified,
157
- avatarUrl: userInfo.picture,
158
- websiteUrl: userInfo.website,
159
- isPro: userInfo.isPro,
160
- orgs: userInfo.orgs || [],
161
- },
162
- state: parsedState.state,
163
- scope: token.scope,
164
- };
165
- }
166
-
167
- const newNonce = crypto.randomUUID();
168
- // Two random UUIDs concatenated together, because min length is 43 and max length is 128
169
- const newCodeVerifier = crypto.randomUUID() + crypto.randomUUID();
170
-
171
- localStorage.setItem("huggingface.co:oauth:nonce", newNonce);
172
- localStorage.setItem("huggingface.co:oauth:code_verifier", newCodeVerifier);
173
-
174
- const redirectUri = opts?.redirectUri || window.location.href;
175
- const state = JSON.stringify({
176
- nonce: newNonce,
177
- redirectUri,
178
- state: opts?.state,
179
- });
180
-
181
- // @ts-expect-error window.huggingface is defined inside static Spaces.
182
- const variables = window?.huggingface?.variables ?? null;
183
-
184
- const clientId = opts?.clientId || variables?.OAUTH_CLIENT_ID;
185
-
186
- if (!clientId) {
187
- if (variables) {
188
- throw new Error("Missing clientId, please add hf_oauth: true to the README.md's metadata in your static Space");
189
- }
190
- throw new Error("Missing clientId");
191
- }
192
-
193
- const challenge = base64FromBytes(
194
- new Uint8Array(await globalThis.crypto.subtle.digest("SHA-256", new TextEncoder().encode(newCodeVerifier)))
195
- )
196
- .replace(/[+]/g, "-")
197
- .replace(/[/]/g, "_")
198
- .replace(/=/g, "");
199
-
200
- console.log("localstorage after", JSON.parse(JSON.stringify(localStorage)))
201
- console.log("challenge after", challenge, newCodeVerifier)
202
-
203
- window.location.href = `${opendidConfig.authorization_endpoint}?${new URLSearchParams({
204
- client_id: clientId,
205
- scope: opts?.scopes || "openid profile",
206
- response_type: "code",
207
- redirect_uri: redirectUri,
208
- state,
209
- code_challenge: challenge,
210
- code_challenge_method: "S256",
211
- }).toString()}`;
212
- throw new Error("Redirected");
213
- }
214
-
215
- oauthLogin().then(console.log);
 
1
+ import { oauthLoginUrl } from "@huggingface/hub";
2
 
3
+ window.location.href = await oauthLoginUrl();