autherr 1.0.11 → 2.0.1

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/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "autherr",
3
- "version": "1.0.11",
3
+ "version": "2.0.1",
4
4
  "dest": "dist",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
7
7
  "build": "tsc -p tsconfig.json"
8
8
  },
9
9
  "dependencies": {
10
+ "jose": "^6.1.3",
10
11
  "react": "^19.2.3"
11
12
  },
12
13
  "devDependencies": {
@@ -0,0 +1,29 @@
1
+ // src/crypto/createClientAssertion.ts
2
+ import { SignJWT } from "jose";
3
+ import { pemToArrayBuffer } from "./pemUtils";
4
+
5
+ export async function createClientAssertion(
6
+ clientId: string,
7
+ privateKeyPem: string
8
+ ): Promise<string> {
9
+ const key = await crypto.subtle.importKey(
10
+ "pkcs8",
11
+ pemToArrayBuffer(privateKeyPem),
12
+ {
13
+ name: "RSASSA-PKCS1-v1_5",
14
+ hash: "SHA-256",
15
+ },
16
+ false,
17
+ ["sign"]
18
+ );
19
+
20
+ const now = Math.floor(Date.now() / 1000);
21
+
22
+ return await new SignJWT({ clientId })
23
+ .setProtectedHeader({ alg: "RS256", typ: "JWT" })
24
+ .setIssuedAt(now)
25
+ .setExpirationTime(now + 120) // ⏱ 2 minutes
26
+ .setAudience("autherr")
27
+ .setIssuer(clientId)
28
+ .sign(key);
29
+ }
@@ -0,0 +1,16 @@
1
+ // src/crypto/pemUtils.ts
2
+ export function pemToArrayBuffer(pem: string): ArrayBuffer {
3
+ const b64 = pem
4
+ .replace(/-----BEGIN [^-]+-----/, "")
5
+ .replace(/-----END [^-]+-----/, "")
6
+ .replace(/\s+/g, "");
7
+
8
+ const binary = atob(b64);
9
+ const bytes = new Uint8Array(binary.length);
10
+
11
+ for (let i = 0; i < binary.length; i++) {
12
+ bytes[i] = binary.charCodeAt(i);
13
+ }
14
+
15
+ return bytes.buffer;
16
+ }
@@ -8,6 +8,7 @@ import React, {
8
8
  import { fetchSession } from "../api/session";
9
9
  import { logoutSession } from "../api/logout";
10
10
  import { AutherrUser } from "../types/auth";
11
+ import { createClientAssertion } from "../crypto/createClientAssertion";
11
12
 
12
13
  interface AutherrContextValue {
13
14
  accessToken: string | null;
@@ -19,6 +20,15 @@ interface AutherrContextValue {
19
20
  refreshSession: () => Promise<void>;
20
21
  }
21
22
 
23
+ function setClientAssertionCookie(token: string) {
24
+ document.cookie =
25
+ `autherr_client_assertion=${token};` +
26
+ `Path=/;` +
27
+ `Secure;` +
28
+ `SameSite=None`;
29
+ }
30
+
31
+
22
32
 
23
33
  const AutherrContext = createContext<AutherrContextValue | null>(null);
24
34
 
@@ -26,12 +36,14 @@ interface AutherrProviderProps {
26
36
  children: React.ReactNode;
27
37
  clientId: string;
28
38
  baseUrl: string; // e.g. https://autherr.com
39
+ clientPrivateKey: string;
29
40
  }
30
41
 
31
42
  export function AutherrProvider({
32
43
  children,
33
44
  clientId,
34
45
  baseUrl,
46
+ clientPrivateKey,
35
47
  }: AutherrProviderProps) {
36
48
 
37
49
  const [accessToken, setAccessToken] = useState<string | null>(null);
@@ -54,8 +66,16 @@ export function AutherrProvider({
54
66
  refreshSession();
55
67
  }, [baseUrl, clientId]);
56
68
 
57
- const login = () => {
69
+ const login = async () => {
58
70
  const state = crypto.randomUUID();
71
+
72
+ const assertion = await createClientAssertion(
73
+ clientId,
74
+ clientPrivateKey
75
+ );
76
+
77
+ setClientAssertionCookie(assertion);
78
+
59
79
  window.location.href =
60
80
  `${baseUrl}/auth/login` +
61
81
  `?client_id=${clientId}` +
@@ -63,8 +83,16 @@ export function AutherrProvider({
63
83
  `&state=${state}`;
64
84
  };
65
85
 
66
- const signup = () => {
86
+ const signup = async () => {
67
87
  const state = crypto.randomUUID();
88
+
89
+ const assertion = await createClientAssertion(
90
+ clientId,
91
+ clientPrivateKey
92
+ );
93
+
94
+ setClientAssertionCookie(assertion);
95
+
68
96
  window.location.href =
69
97
  `${baseUrl}/auth/signup` +
70
98
  `?client_id=${clientId}` +
@@ -72,6 +100,7 @@ export function AutherrProvider({
72
100
  `&state=${state}`;
73
101
  };
74
102
 
103
+
75
104
  const logout = async () => {
76
105
  try {
77
106
  await logoutSession(baseUrl, clientId);