@o/better-auth-utils 0.16.19
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/LICENSE +21 -0
- package/README.md +105 -0
- package/dist/cjs/createAuthClient.cjs +251 -0
- package/dist/cjs/createAuthClient.native.js +279 -0
- package/dist/cjs/createAuthClient.native.js.map +1 -0
- package/dist/cjs/createAuthClient.test.cjs +88 -0
- package/dist/cjs/createAuthClient.test.native.js +105 -0
- package/dist/cjs/createAuthClient.test.native.js.map +1 -0
- package/dist/cjs/index.cjs +20 -0
- package/dist/cjs/index.native.js +23 -0
- package/dist/cjs/index.native.js.map +1 -0
- package/dist/cjs/server.cjs +106 -0
- package/dist/cjs/server.native.js +228 -0
- package/dist/cjs/server.native.js.map +1 -0
- package/dist/esm/createAuthClient.mjs +226 -0
- package/dist/esm/createAuthClient.mjs.map +1 -0
- package/dist/esm/createAuthClient.native.js +251 -0
- package/dist/esm/createAuthClient.native.js.map +1 -0
- package/dist/esm/createAuthClient.test.mjs +89 -0
- package/dist/esm/createAuthClient.test.mjs.map +1 -0
- package/dist/esm/createAuthClient.test.native.js +103 -0
- package/dist/esm/createAuthClient.test.native.js.map +1 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/index.mjs +2 -0
- package/dist/esm/index.mjs.map +1 -0
- package/dist/esm/index.native.js +2 -0
- package/dist/esm/index.native.js.map +1 -0
- package/dist/esm/server.mjs +77 -0
- package/dist/esm/server.mjs.map +1 -0
- package/dist/esm/server.native.js +196 -0
- package/dist/esm/server.native.js.map +1 -0
- package/package.json +66 -0
- package/src/createAuthClient.test.ts +86 -0
- package/src/createAuthClient.ts +373 -0
- package/src/index.ts +1 -0
- package/src/server.ts +150 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, test, vi } from "vitest";
|
|
2
|
+
import { createBetterAuthClient } from "./createAuthClient.native.js";
|
|
3
|
+
var mocks = vi.hoisted(function () {
|
|
4
|
+
return {
|
|
5
|
+
createAuthClient: vi.fn(),
|
|
6
|
+
request: vi.fn()
|
|
7
|
+
};
|
|
8
|
+
});
|
|
9
|
+
vi.mock("better-auth/client", function () {
|
|
10
|
+
return {
|
|
11
|
+
createAuthClient: mocks.createAuthClient
|
|
12
|
+
};
|
|
13
|
+
});
|
|
14
|
+
vi.mock("@o/helpers", function () {
|
|
15
|
+
return {
|
|
16
|
+
createEmitter: function createEmitter(_name, initialValue) {
|
|
17
|
+
var emitter = {
|
|
18
|
+
value: initialValue,
|
|
19
|
+
emit(value) {
|
|
20
|
+
emitter.value = value;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
return emitter;
|
|
24
|
+
},
|
|
25
|
+
createStorageValue: function createStorageValue() {
|
|
26
|
+
return {
|
|
27
|
+
get: function get() {
|
|
28
|
+
return void 0;
|
|
29
|
+
},
|
|
30
|
+
set: vi.fn(),
|
|
31
|
+
remove: vi.fn()
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
isEqualDeepLite: Object.is,
|
|
35
|
+
useEmitterValue: function useEmitterValue(emitter) {
|
|
36
|
+
return emitter.value;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
describe("createBetterAuthClient signOut", function () {
|
|
41
|
+
beforeEach(function () {
|
|
42
|
+
mocks.request.mockReset();
|
|
43
|
+
mocks.createAuthClient.mockReset();
|
|
44
|
+
mocks.createAuthClient.mockReturnValue({
|
|
45
|
+
$fetch: mocks.request,
|
|
46
|
+
useSession: {
|
|
47
|
+
subscribe: vi.fn(function () {
|
|
48
|
+
return vi.fn();
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
test("sends JSON and clears local auth only after server revocation succeeds", async function () {
|
|
54
|
+
var deferred = Promise.withResolvers();
|
|
55
|
+
mocks.request.mockReturnValue(deferred.promise);
|
|
56
|
+
var onAuthStateChange = vi.fn();
|
|
57
|
+
var client = createBetterAuthClient({
|
|
58
|
+
baseURL: "https://auth.example.com",
|
|
59
|
+
onAuthStateChange
|
|
60
|
+
});
|
|
61
|
+
var pending = client.authClient.signOut();
|
|
62
|
+
expect(mocks.request).toHaveBeenCalledWith("/sign-out", {
|
|
63
|
+
method: "POST",
|
|
64
|
+
body: {}
|
|
65
|
+
});
|
|
66
|
+
expect(onAuthStateChange).not.toHaveBeenCalled();
|
|
67
|
+
deferred.resolve({
|
|
68
|
+
data: {
|
|
69
|
+
success: true
|
|
70
|
+
},
|
|
71
|
+
error: null
|
|
72
|
+
});
|
|
73
|
+
await expect(pending).resolves.toEqual({
|
|
74
|
+
data: {
|
|
75
|
+
success: true
|
|
76
|
+
},
|
|
77
|
+
error: null
|
|
78
|
+
});
|
|
79
|
+
expect(onAuthStateChange).toHaveBeenCalledWith({
|
|
80
|
+
state: "logged-out",
|
|
81
|
+
session: null,
|
|
82
|
+
user: null,
|
|
83
|
+
token: null
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
test("keeps local auth when server revocation fails", async function () {
|
|
87
|
+
var error = {
|
|
88
|
+
message: "network unavailable"
|
|
89
|
+
};
|
|
90
|
+
mocks.request.mockResolvedValue({
|
|
91
|
+
data: null,
|
|
92
|
+
error
|
|
93
|
+
});
|
|
94
|
+
var onAuthStateChange = vi.fn();
|
|
95
|
+
var client = createBetterAuthClient({
|
|
96
|
+
baseURL: "https://auth.example.com",
|
|
97
|
+
onAuthStateChange
|
|
98
|
+
});
|
|
99
|
+
await expect(client.authClient.signOut()).rejects.toBe(error);
|
|
100
|
+
expect(onAuthStateChange).not.toHaveBeenCalled();
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
//# sourceMappingURL=createAuthClient.test.native.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["beforeEach","describe","expect","test","vi","createBetterAuthClient","mocks","hoisted","createAuthClient","fn","request","mock","createEmitter","_name","initialValue","emitter","value","emit","createStorageValue","get","set","remove","isEqualDeepLite","Object","is","useEmitterValue","mockReset","mockReturnValue","$fetch","useSession","subscribe","deferred","Promise","withResolvers","promise","onAuthStateChange","client","baseURL","pending","authClient","signOut","toHaveBeenCalledWith","method","body","not","toHaveBeenCalled","resolve","data","success","error","resolves","toEqual"],"sources":["../../src/createAuthClient.test.ts"],"sourcesContent":[null],"mappings":"AAAA,SAASA,UAAA,EAAYC,QAAA,EAAUC,MAAA,EAAQC,IAAA,EAAMC,EAAA,QAAU;AA8BvD,SAASC,sBAAA,QAA8B;AA5BvC,IAAAC,KAAM,GAAAF,EAAQ,CAAAG,OAAG,aAAe;EAC9B;IACAC,gBAAe,EAAAJ,EAAA,CAAAK,EAAA;IACfC,OAAA,EAAAN,EAAA,CAAAK,EAAA;EAEF,CAAG;AAAkC,EACnC;AACFL,EAAE,CAAAO,IAAA;EAEF,OAAQ;IACNH,gBAAgB,EAAAF,KAAe,CAAAE;EAC7B;AAAgB;AACPJ,EAAA,CAAAO,IACP,aAAqB;EACnB;IAAgBC,aAClB,WAAAA,cAAAC,KAAA,EAAAC,YAAA;MACF,IAAAC,OAAA;QACAC,KAAO,EAAAF,YAAA;QACTG,KAAAD,KAAA;UACAD,OAAA,CAAAC,KAAoB,GAAAA,KAAO;QACzB;MACA;MACA,OAAQD,OAAM;IAChB;IACAG,kBAAiB,WAAOA,mBAAA;MACxB;QACAC,GAAA,WAAAA,IAAA;UAIO;QACP;QACEC,GAAM,EAAAhB,EAAA,CAAAK,EAAQ;QACdY,MAAM,EAAAjB,EAAA,CAAAK,EAAA;MACN;IAAuC;IACvBa,eACF,EAAAC,MAAA,CAAAC,EAAA;IAAAC,eACC,WAAMA,eAAaA,CAAAV,OAAA;MAChC,OAAAA,OAAA,CAAAC,KAAA;IACF;EACF,CAAC;AAED;AACEf,QAAA,iCAAyB,EAGtB;EACHD,UAAM,aAAQ;IACdM,KAAA,CAAMI,OAAA,CAAAgB,SAAA;IACNpB,KAAA,CAAME,gBAAS,CAAAkB,SAAA;IAAuBpB,KACpC,CAAAE,gBAAS,CAAAmB,eAAA;MACTC,MAAA,EAAAtB,KAAA,CAAAI,OAAA;MACDmB,UAAA;QAEDC,SAAM,EAAA1B,EAAU,CAAAK,EAAA,aAAO;UACvB,OAAaL,EAAA,CAAAK,EAAA,EAAO;QAClB;MACA;IACF,CAAC;EACD;EAEAN,IAAA,yEAAyD;IACzD,IAAA4B,QAAM,GAAOC,OAAS,CAAAC,aAAS;IAC/B3B,KAAA,CAAAI,OAAO,CAAAiB,eAAmB,CAAAI,QAAA,CAAAG,OAAA,CAAqB;IAAA,IAC7CC,iBAAO,GAAA/B,EAAA,CAAAK,EAAA;IAAA,IACP2B,MAAA,GAAS/B,sBAAA;MACTgC,OAAM;MACNF;IACF,CAAC;IACF,IAAAG,OAAA,GAAAF,MAAA,CAAAG,UAAA,CAAAC,OAAA;IAEDtC,MAAK,CAAAI,KAAA,CAAAI,OAAA,EAAA+B,oBAAA,YAAiD;MACpDC,MAAM,QAAU;MAChBC,IAAM;IACN;IACAzC,MAAM,CAAAiC,iBAAS,EAAAS,GAAA,CAAAC,gBAAuB;IAAAd,QACpC,CAAAe,OAAS;MACTC,IAAA;QACDC,OAAA;MAED;MACAC,KAAO;IACR;IACF,MAAA/C,MAAA,CAAAoC,OAAA,EAAAY,QAAA,CAAAC,OAAA","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sources":["../../src/index.ts"],"sourcesContent":[null],"mappings":"AAAA,cAAc","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sources":["../../src/index.ts"],"sourcesContent":[null],"mappings":"AAAA,cAAc","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sources":["../../src/index.ts"],"sourcesContent":[null],"mappings":"AAAA,cAAc","ignoreList":[]}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { createRemoteJWKSet, jwtVerify } from "jose";
|
|
2
|
+
class NotAuthenticatedError extends Error {}
|
|
3
|
+
class InvalidTokenError extends Error {}
|
|
4
|
+
async function getAuthDataFromRequest(authServer, req, tokenOptions) {
|
|
5
|
+
const authHeader = req.headers.get("authorization");
|
|
6
|
+
try {
|
|
7
|
+
const session = await authServer.api.getSession({
|
|
8
|
+
headers: req.headers
|
|
9
|
+
});
|
|
10
|
+
if (session?.user) {
|
|
11
|
+
return {
|
|
12
|
+
id: session.user.id,
|
|
13
|
+
email: session.user.email || void 0,
|
|
14
|
+
role: session.user.role === "admin" ? "admin" : void 0
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
} catch (err) {
|
|
18
|
+
console.warn(`Error validating session`, err);
|
|
19
|
+
}
|
|
20
|
+
const jwtToken = authHeader?.replace("Bearer ", "");
|
|
21
|
+
if (jwtToken) {
|
|
22
|
+
try {
|
|
23
|
+
const payload = await validateToken(jwtToken, tokenOptions);
|
|
24
|
+
const userId = payload?.id || payload?.sub;
|
|
25
|
+
if (userId) {
|
|
26
|
+
return {
|
|
27
|
+
id: userId,
|
|
28
|
+
email: payload.email,
|
|
29
|
+
role: payload.role === "admin" ? "admin" : void 0
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
} catch (err) {
|
|
33
|
+
if (!(err instanceof InvalidTokenError)) {
|
|
34
|
+
throw err;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
async function validateToken(token, options) {
|
|
41
|
+
const {
|
|
42
|
+
baseUrl = process.env.ONE_SERVER_URL,
|
|
43
|
+
forceIssuer = process.env.FORCE_ISSUER || "",
|
|
44
|
+
jwksPath = "/api/auth/jwks"
|
|
45
|
+
} = options || {};
|
|
46
|
+
if (!baseUrl) {
|
|
47
|
+
throw new Error(`No baseURL!`);
|
|
48
|
+
}
|
|
49
|
+
const normalizedBaseUrl = removeTrailingSlash(baseUrl);
|
|
50
|
+
const url = `${forceIssuer || normalizedBaseUrl}${jwksPath}`;
|
|
51
|
+
const JWKS = createRemoteJWKSet(new URL(url));
|
|
52
|
+
try {
|
|
53
|
+
const verifyOptions = forceIssuer ? {} : {
|
|
54
|
+
issuer: normalizedBaseUrl,
|
|
55
|
+
audience: normalizedBaseUrl
|
|
56
|
+
};
|
|
57
|
+
const {
|
|
58
|
+
payload
|
|
59
|
+
} = await jwtVerify(token, JWKS, verifyOptions);
|
|
60
|
+
return payload;
|
|
61
|
+
} catch (error) {
|
|
62
|
+
throw new InvalidTokenError(`${error}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async function isValidJWT(token, options) {
|
|
66
|
+
try {
|
|
67
|
+
await validateToken(token, options);
|
|
68
|
+
return true;
|
|
69
|
+
} catch {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function removeTrailingSlash(str) {
|
|
74
|
+
return str.replace(/\/$/, "");
|
|
75
|
+
}
|
|
76
|
+
export { InvalidTokenError, NotAuthenticatedError, getAuthDataFromRequest, isValidJWT, validateToken };
|
|
77
|
+
//# sourceMappingURL=server.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["createRemoteJWKSet","jwtVerify","NotAuthenticatedError","Error","InvalidTokenError","getAuthDataFromRequest","authServer","req","tokenOptions","authHeader","headers","get","session","api","getSession","user","id","email","role","err","console","warn","jwtToken","replace","payload","validateToken","userId","sub","token","options","baseUrl","process","env","ONE_SERVER_URL","forceIssuer","FORCE_ISSUER","jwksPath","normalizedBaseUrl","removeTrailingSlash","url","JWKS","URL","verifyOptions","issuer","audience","error","isValidJWT","str"],"sources":["../../src/server.ts"],"sourcesContent":[null],"mappings":"AAMA,SAASA,kBAAA,EAAoBC,SAAA,QAAkC;AAiBxD,MAAMC,qBAAA,SAA8BC,KAAA,CAAM;AAC1C,MAAMC,iBAAA,SAA0BD,KAAA,CAAM;AAkB7C,eAAsBE,uBACpBC,UAAA,EACAC,GAAA,EACAC,YAAA,EAC0B;EAC1B,MAAMC,UAAA,GAAaF,GAAA,CAAIG,OAAA,CAAQC,GAAA,CAAI,eAAe;EAWlD,IAAI;IACF,MAAMC,OAAA,GAAU,MAAMN,UAAA,CAAWO,GAAA,CAAIC,UAAA,CAAW;MAAEJ,OAAA,EAASH,GAAA,CAAIG;IAAQ,CAAC;IACxE,IAAIE,OAAA,EAASG,IAAA,EAAM;MACjB,OAAO;QACLC,EAAA,EAAIJ,OAAA,CAAQG,IAAA,CAAKC,EAAA;QACjBC,KAAA,EAAOL,OAAA,CAAQG,IAAA,CAAKE,KAAA,IAAS;QAC7BC,IAAA,EAAMN,OAAA,CAAQG,IAAA,CAAKG,IAAA,KAAS,UAAU,UAAU;MAClD;IACF;EACF,SAASC,GAAA,EAAK;IACZC,OAAA,CAAQC,IAAA,CAAK,4BAA4BF,GAAG;EAE9C;EAIA,MAAMG,QAAA,GAAWb,UAAA,EAAYc,OAAA,CAAQ,WAAW,EAAE;EAElD,IAAID,QAAA,EAAU;IACZ,IAAI;MACF,MAAME,OAAA,GAAU,MAAMC,aAAA,CAAcH,QAAA,EAAUd,YAAY;MAC1D,MAAMkB,MAAA,GAAUF,OAAA,EAAiBR,EAAA,IAAMQ,OAAA,EAASG,GAAA;MAChD,IAAID,MAAA,EAAQ;QACV,OAAO;UACLV,EAAA,EAAIU,MAAA;UACJT,KAAA,EAAQO,OAAA,CAAgBP,KAAA;UACxBC,IAAA,EAAOM,OAAA,CAAgBN,IAAA,KAAS,UAAU,UAAU;QACtD;MACF;IACF,SAASC,GAAA,EAAK;MACZ,IAAI,EAAEA,GAAA,YAAef,iBAAA,GAAoB;QACvC,MAAMe,GAAA;MACR;IACF;EACF;EAEA,OAAO;AACT;AAIA,eAAsBM,cACpBG,KAAA,EACAC,OAAA,EACqB;EACrB,MAAM;IACJC,OAAA,GAAUC,OAAA,CAAQC,GAAA,CAAIC,cAAA;IACtBC,WAAA,GAAcH,OAAA,CAAQC,GAAA,CAAIG,YAAA,IAAgB;IAC1CC,QAAA,GAAW;EACb,IAAIP,OAAA,IAAW,CAAC;EAEhB,IAAI,CAACC,OAAA,EAAS;IACZ,MAAM,IAAI3B,KAAA,CAAM,aAAa;EAC/B;EAEA,MAAMkC,iBAAA,GAAoBC,mBAAA,CAAoBR,OAAO;EACrD,MAAMS,GAAA,GAAM,GAAGL,WAAA,IAAeG,iBAAiB,GAAGD,QAAQ;EAG1D,MAAMI,IAAA,GAAOxC,kBAAA,CAAmB,IAAIyC,GAAA,CAAIF,GAAG,CAAC;EAE5C,IAAI;IACF,MAAMG,aAAA,GAAgBR,WAAA,GAClB,CAAC,IACD;MACES,MAAA,EAAQN,iBAAA;MACRO,QAAA,EAAUP;IACZ;IAEJ,MAAM;MAAEb;IAAQ,IAAI,MAAMvB,SAAA,CAAU2B,KAAA,EAAOY,IAAA,EAAME,aAAa;IAE9D,OAAOlB,OAAA;EACT,SAASqB,KAAA,EAAO;IACd,MAAM,IAAIzC,iBAAA,CAAkB,GAAGyC,KAAK,EAAE;EACxC;AACF;AAEA,eAAsBC,WACpBlB,KAAA,EACAC,OAAA,EACkB;EAClB,IAAI;IACF,MAAMJ,aAAA,CAAcG,KAAA,EAAOC,OAAO;IAClC,OAAO;EACT,QAAQ;IACN,OAAO;EACT;AACF;AAEA,SAASS,oBAAoBS,GAAA,EAAa;EACxC,OAAOA,GAAA,CAAIxB,OAAA,CAAQ,OAAO,EAAE;AAC9B","ignoreList":[]}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { createRemoteJWKSet, jwtVerify } from "jose";
|
|
2
|
+
function _assert_this_initialized(self) {
|
|
3
|
+
if (self === void 0) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
|
|
4
|
+
return self;
|
|
5
|
+
}
|
|
6
|
+
function _call_super(_this, derived, args) {
|
|
7
|
+
derived = _get_prototype_of(derived);
|
|
8
|
+
return _possible_constructor_return(_this, _is_native_reflect_construct() ? Reflect.construct(derived, args || [], _get_prototype_of(_this).constructor) : derived.apply(_this, args));
|
|
9
|
+
}
|
|
10
|
+
function _class_call_check(instance, Constructor) {
|
|
11
|
+
if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function");
|
|
12
|
+
}
|
|
13
|
+
function _construct(Parent, args, Class) {
|
|
14
|
+
if (_is_native_reflect_construct()) _construct = Reflect.construct;else {
|
|
15
|
+
_construct = function construct(Parent2, args2, Class2) {
|
|
16
|
+
var a = [null];
|
|
17
|
+
a.push.apply(a, args2);
|
|
18
|
+
var Constructor = Function.bind.apply(Parent2, a);
|
|
19
|
+
var instance = new Constructor();
|
|
20
|
+
if (Class2) _set_prototype_of(instance, Class2.prototype);
|
|
21
|
+
return instance;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
return _construct.apply(null, arguments);
|
|
25
|
+
}
|
|
26
|
+
function _get_prototype_of(o) {
|
|
27
|
+
_get_prototype_of = Object.setPrototypeOf ? Object.getPrototypeOf : function getPrototypeOf(o2) {
|
|
28
|
+
return o2.__proto__ || Object.getPrototypeOf(o2);
|
|
29
|
+
};
|
|
30
|
+
return _get_prototype_of(o);
|
|
31
|
+
}
|
|
32
|
+
function _inherits(subClass, superClass) {
|
|
33
|
+
if (typeof superClass !== "function" && superClass !== null) {
|
|
34
|
+
throw new TypeError("Super expression must either be null or a function");
|
|
35
|
+
}
|
|
36
|
+
subClass.prototype = Object.create(superClass && superClass.prototype, {
|
|
37
|
+
constructor: {
|
|
38
|
+
value: subClass,
|
|
39
|
+
writable: true,
|
|
40
|
+
configurable: true
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
if (superClass) _set_prototype_of(subClass, superClass);
|
|
44
|
+
}
|
|
45
|
+
function _instanceof(left, right) {
|
|
46
|
+
"@swc/helpers - instanceof";
|
|
47
|
+
|
|
48
|
+
if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
|
|
49
|
+
return !!right[Symbol.hasInstance](left);
|
|
50
|
+
} else return left instanceof right;
|
|
51
|
+
}
|
|
52
|
+
function _is_native_function(fn) {
|
|
53
|
+
return Function.toString.call(fn).indexOf("[native code]") !== -1;
|
|
54
|
+
}
|
|
55
|
+
function _is_native_reflect_construct() {
|
|
56
|
+
try {
|
|
57
|
+
var result = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
|
|
58
|
+
} catch (_) {}
|
|
59
|
+
return (_is_native_reflect_construct = function () {
|
|
60
|
+
return !!result;
|
|
61
|
+
})();
|
|
62
|
+
}
|
|
63
|
+
function _possible_constructor_return(self, call) {
|
|
64
|
+
if (call && (_type_of(call) === "object" || typeof call === "function")) return call;
|
|
65
|
+
return _assert_this_initialized(self);
|
|
66
|
+
}
|
|
67
|
+
function _set_prototype_of(o, p) {
|
|
68
|
+
_set_prototype_of = Object.setPrototypeOf || function setPrototypeOf(o2, p2) {
|
|
69
|
+
o2.__proto__ = p2;
|
|
70
|
+
return o2;
|
|
71
|
+
};
|
|
72
|
+
return _set_prototype_of(o, p);
|
|
73
|
+
}
|
|
74
|
+
function _type_of(obj) {
|
|
75
|
+
"@swc/helpers - typeof";
|
|
76
|
+
|
|
77
|
+
return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
|
|
78
|
+
}
|
|
79
|
+
function _wrap_native_super(Class) {
|
|
80
|
+
var _cache = typeof Map === "function" ? /* @__PURE__ */new Map() : void 0;
|
|
81
|
+
_wrap_native_super = function (Class2) {
|
|
82
|
+
if (Class2 === null || !_is_native_function(Class2)) return Class2;
|
|
83
|
+
if (typeof Class2 !== "function") throw new TypeError("Super expression must either be null or a function");
|
|
84
|
+
if (typeof _cache !== "undefined") {
|
|
85
|
+
if (_cache.has(Class2)) return _cache.get(Class2);
|
|
86
|
+
_cache.set(Class2, Wrapper);
|
|
87
|
+
}
|
|
88
|
+
function Wrapper() {
|
|
89
|
+
return _construct(Class2, arguments, _get_prototype_of(this).constructor);
|
|
90
|
+
}
|
|
91
|
+
Wrapper.prototype = Object.create(Class2.prototype, {
|
|
92
|
+
constructor: {
|
|
93
|
+
value: Wrapper,
|
|
94
|
+
enumerable: false,
|
|
95
|
+
writable: true,
|
|
96
|
+
configurable: true
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
return _set_prototype_of(Wrapper, Class2);
|
|
100
|
+
};
|
|
101
|
+
return _wrap_native_super(Class);
|
|
102
|
+
}
|
|
103
|
+
var NotAuthenticatedError = /* @__PURE__ */function (Error1) {
|
|
104
|
+
"use strict";
|
|
105
|
+
|
|
106
|
+
_inherits(NotAuthenticatedError2, Error1);
|
|
107
|
+
function NotAuthenticatedError2() {
|
|
108
|
+
_class_call_check(this, NotAuthenticatedError2);
|
|
109
|
+
return _call_super(this, NotAuthenticatedError2, arguments);
|
|
110
|
+
}
|
|
111
|
+
return NotAuthenticatedError2;
|
|
112
|
+
}(_wrap_native_super(Error));
|
|
113
|
+
var InvalidTokenError = /* @__PURE__ */function (Error1) {
|
|
114
|
+
"use strict";
|
|
115
|
+
|
|
116
|
+
_inherits(InvalidTokenError2, Error1);
|
|
117
|
+
function InvalidTokenError2() {
|
|
118
|
+
_class_call_check(this, InvalidTokenError2);
|
|
119
|
+
return _call_super(this, InvalidTokenError2, arguments);
|
|
120
|
+
}
|
|
121
|
+
return InvalidTokenError2;
|
|
122
|
+
}(_wrap_native_super(Error));
|
|
123
|
+
async function getAuthDataFromRequest(authServer, req, tokenOptions) {
|
|
124
|
+
var authHeader = req.headers.get("authorization");
|
|
125
|
+
try {
|
|
126
|
+
var session = await authServer.api.getSession({
|
|
127
|
+
headers: req.headers
|
|
128
|
+
});
|
|
129
|
+
if (session === null || session === void 0 ? void 0 : session.user) {
|
|
130
|
+
return {
|
|
131
|
+
id: session.user.id,
|
|
132
|
+
email: session.user.email || void 0,
|
|
133
|
+
role: session.user.role === "admin" ? "admin" : void 0
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
} catch (err) {
|
|
137
|
+
console.warn(`Error validating session`, err);
|
|
138
|
+
}
|
|
139
|
+
var jwtToken = authHeader === null || authHeader === void 0 ? void 0 : authHeader.replace("Bearer ", "");
|
|
140
|
+
if (jwtToken) {
|
|
141
|
+
try {
|
|
142
|
+
var payload = await validateToken(jwtToken, tokenOptions);
|
|
143
|
+
var userId = (payload === null || payload === void 0 ? void 0 : payload.id) || (payload === null || payload === void 0 ? void 0 : payload.sub);
|
|
144
|
+
if (userId) {
|
|
145
|
+
return {
|
|
146
|
+
id: userId,
|
|
147
|
+
email: payload.email,
|
|
148
|
+
role: payload.role === "admin" ? "admin" : void 0
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
} catch (err) {
|
|
152
|
+
if (!_instanceof(err, InvalidTokenError)) {
|
|
153
|
+
throw err;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
async function validateToken(token, options) {
|
|
160
|
+
var {
|
|
161
|
+
baseUrl = process.env.ONE_SERVER_URL,
|
|
162
|
+
forceIssuer = process.env.FORCE_ISSUER || "",
|
|
163
|
+
jwksPath = "/api/auth/jwks"
|
|
164
|
+
} = options || {};
|
|
165
|
+
if (!baseUrl) {
|
|
166
|
+
throw new Error(`No baseURL!`);
|
|
167
|
+
}
|
|
168
|
+
var normalizedBaseUrl = removeTrailingSlash(baseUrl);
|
|
169
|
+
var url = `${forceIssuer || normalizedBaseUrl}${jwksPath}`;
|
|
170
|
+
var JWKS = createRemoteJWKSet(new URL(url));
|
|
171
|
+
try {
|
|
172
|
+
var verifyOptions = forceIssuer ? {} : {
|
|
173
|
+
issuer: normalizedBaseUrl,
|
|
174
|
+
audience: normalizedBaseUrl
|
|
175
|
+
};
|
|
176
|
+
var {
|
|
177
|
+
payload
|
|
178
|
+
} = await jwtVerify(token, JWKS, verifyOptions);
|
|
179
|
+
return payload;
|
|
180
|
+
} catch (error) {
|
|
181
|
+
throw new InvalidTokenError(`${error}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
async function isValidJWT(token, options) {
|
|
185
|
+
try {
|
|
186
|
+
await validateToken(token, options);
|
|
187
|
+
return true;
|
|
188
|
+
} catch (unused) {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function removeTrailingSlash(str) {
|
|
193
|
+
return str.replace(/\/$/, "");
|
|
194
|
+
}
|
|
195
|
+
export { InvalidTokenError, NotAuthenticatedError, getAuthDataFromRequest, isValidJWT, validateToken };
|
|
196
|
+
//# sourceMappingURL=server.native.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["createRemoteJWKSet","jwtVerify","_assert_this_initialized","self","ReferenceError","_call_super","_this","derived","args","_get_prototype_of","_possible_constructor_return","_is_native_reflect_construct","Reflect","construct","constructor","apply","_class_call_check","instance","Constructor","TypeError","_construct","Parent","Class","Parent2","args2","Class2","a","push","Function","bind","_set_prototype_of","prototype","arguments","o","Object","setPrototypeOf","getPrototypeOf","o2","__proto__","_inherits","subClass","superClass","create","value","writable","configurable","_instanceof","left","right","Symbol","hasInstance","_is_native_function","fn","toString","call","indexOf","result","Boolean","valueOf","_","_type_of","p","p2"],"sources":["../../src/server.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@o/better-auth-utils",
|
|
3
|
+
"version": "0.16.19",
|
|
4
|
+
"description": "Better auth utilities and client for React/React Native applications",
|
|
5
|
+
"sideEffects": false,
|
|
6
|
+
"type": "module",
|
|
7
|
+
"source": "src/index.ts",
|
|
8
|
+
"main": "dist/cjs",
|
|
9
|
+
"module": "dist/esm",
|
|
10
|
+
"types": "./src/index.ts",
|
|
11
|
+
"files": [
|
|
12
|
+
"src",
|
|
13
|
+
"dist"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tamagui-build --skip-types",
|
|
17
|
+
"watch": "tamagui-build --skip-types --watch",
|
|
18
|
+
"test": "vitest run",
|
|
19
|
+
"lint": "oxlint src",
|
|
20
|
+
"lint:fix": "oxfmt src && oxlint --fix --fix-suggestions src",
|
|
21
|
+
"clean": "tamagui-build clean",
|
|
22
|
+
"clean:build": "tamagui-build clean:build"
|
|
23
|
+
},
|
|
24
|
+
"exports": {
|
|
25
|
+
"./package.json": "./package.json",
|
|
26
|
+
".": {
|
|
27
|
+
"react-native": "./dist/esm/index.native.js",
|
|
28
|
+
"types": "./src/index.ts",
|
|
29
|
+
"import": "./dist/esm/index.mjs",
|
|
30
|
+
"require": "./dist/cjs/index.cjs",
|
|
31
|
+
"default": "./dist/esm/index.mjs"
|
|
32
|
+
},
|
|
33
|
+
"./server": {
|
|
34
|
+
"types": "./src/server.ts",
|
|
35
|
+
"import": "./dist/esm/server.mjs",
|
|
36
|
+
"require": "./dist/cjs/server.cjs",
|
|
37
|
+
"default": "./dist/esm/server.mjs"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@o/helpers": "0.16.19",
|
|
42
|
+
"jose": "^6.0.10"
|
|
43
|
+
},
|
|
44
|
+
"peerDependencies": {
|
|
45
|
+
"better-auth": "^1.6.23",
|
|
46
|
+
"react": "*"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@tamagui/build": "2.3.1",
|
|
50
|
+
"@types/node": "24.0.3",
|
|
51
|
+
"@types/react": "^19.0.8",
|
|
52
|
+
"oxfmt": "^0.16.0",
|
|
53
|
+
"oxlint": "^1.31.0",
|
|
54
|
+
"react": "*",
|
|
55
|
+
"vitest": "4.1.11"
|
|
56
|
+
},
|
|
57
|
+
"publishConfig": {
|
|
58
|
+
"access": "public"
|
|
59
|
+
},
|
|
60
|
+
"repository": {
|
|
61
|
+
"type": "git",
|
|
62
|
+
"url": "git+https://github.com/natew/orez.git",
|
|
63
|
+
"directory": "packages/better-auth-utils"
|
|
64
|
+
},
|
|
65
|
+
"optionalDependencies": null
|
|
66
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, test, vi } from 'vitest'
|
|
2
|
+
|
|
3
|
+
const mocks = vi.hoisted(() => ({
|
|
4
|
+
createAuthClient: vi.fn(),
|
|
5
|
+
request: vi.fn(),
|
|
6
|
+
}))
|
|
7
|
+
|
|
8
|
+
vi.mock('better-auth/client', () => ({
|
|
9
|
+
createAuthClient: mocks.createAuthClient,
|
|
10
|
+
}))
|
|
11
|
+
|
|
12
|
+
vi.mock('@o/helpers', () => ({
|
|
13
|
+
createEmitter: (_name: string, initialValue: unknown) => {
|
|
14
|
+
const emitter = {
|
|
15
|
+
value: initialValue,
|
|
16
|
+
emit(value: unknown) {
|
|
17
|
+
emitter.value = value
|
|
18
|
+
},
|
|
19
|
+
}
|
|
20
|
+
return emitter
|
|
21
|
+
},
|
|
22
|
+
createStorageValue: () => ({
|
|
23
|
+
get: () => undefined,
|
|
24
|
+
set: vi.fn(),
|
|
25
|
+
remove: vi.fn(),
|
|
26
|
+
}),
|
|
27
|
+
isEqualDeepLite: Object.is,
|
|
28
|
+
useEmitterValue: (emitter: { value: unknown }) => emitter.value,
|
|
29
|
+
}))
|
|
30
|
+
|
|
31
|
+
import { createBetterAuthClient } from './createAuthClient'
|
|
32
|
+
|
|
33
|
+
describe('createBetterAuthClient signOut', () => {
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
mocks.request.mockReset()
|
|
36
|
+
mocks.createAuthClient.mockReset()
|
|
37
|
+
mocks.createAuthClient.mockReturnValue({
|
|
38
|
+
$fetch: mocks.request,
|
|
39
|
+
useSession: {
|
|
40
|
+
subscribe: vi.fn(() => vi.fn()),
|
|
41
|
+
},
|
|
42
|
+
})
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
test('sends JSON and clears local auth only after server revocation succeeds', async () => {
|
|
46
|
+
const deferred = Promise.withResolvers<{
|
|
47
|
+
data: { success: true }
|
|
48
|
+
error: null
|
|
49
|
+
}>()
|
|
50
|
+
mocks.request.mockReturnValue(deferred.promise)
|
|
51
|
+
const onAuthStateChange = vi.fn()
|
|
52
|
+
const client = createBetterAuthClient({
|
|
53
|
+
baseURL: 'https://auth.example.com',
|
|
54
|
+
onAuthStateChange,
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
const pending = client.authClient.signOut()
|
|
58
|
+
expect(mocks.request).toHaveBeenCalledWith('/sign-out', {
|
|
59
|
+
method: 'POST',
|
|
60
|
+
body: {},
|
|
61
|
+
})
|
|
62
|
+
expect(onAuthStateChange).not.toHaveBeenCalled()
|
|
63
|
+
|
|
64
|
+
deferred.resolve({ data: { success: true }, error: null })
|
|
65
|
+
await expect(pending).resolves.toEqual({ data: { success: true }, error: null })
|
|
66
|
+
expect(onAuthStateChange).toHaveBeenCalledWith({
|
|
67
|
+
state: 'logged-out',
|
|
68
|
+
session: null,
|
|
69
|
+
user: null,
|
|
70
|
+
token: null,
|
|
71
|
+
})
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
test('keeps local auth when server revocation fails', async () => {
|
|
75
|
+
const error = { message: 'network unavailable' }
|
|
76
|
+
mocks.request.mockResolvedValue({ data: null, error })
|
|
77
|
+
const onAuthStateChange = vi.fn()
|
|
78
|
+
const client = createBetterAuthClient({
|
|
79
|
+
baseURL: 'https://auth.example.com',
|
|
80
|
+
onAuthStateChange,
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
await expect(client.authClient.signOut()).rejects.toBe(error)
|
|
84
|
+
expect(onAuthStateChange).not.toHaveBeenCalled()
|
|
85
|
+
})
|
|
86
|
+
})
|