Skip to content

Commit a232499

Browse files
committed
feat: add csrf-token handling
1 parent c86ac2a commit a232499

File tree

4 files changed

+81
-29
lines changed

4 files changed

+81
-29
lines changed

src/contexts/AuthProvider.tsx

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,9 @@ const AuthProvider: React.FC<AuthProviderProps> = ({ config, children }) => {
1010
const [currentConfig, setCurrentConfig] = useState<AuthConfig>(config);
1111
const [currentUser, setCurrentUser] = useState<User | null>(null);
1212
const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
13-
const [authService, setAuthService] = useState<AuthService>();
13+
const [authService, setAuthService] = useState<AuthService | undefined>();
1414

1515
useEffect(() => {
16-
console.log('checking if authenticated');
1716
if (authService) {
1817
checkIfAuthenticated();
1918
}
@@ -39,7 +38,7 @@ const AuthProvider: React.FC<AuthProviderProps> = ({ config, children }) => {
3938
}
4039
});
4140
} catch (error) {
42-
console.error('Fehler beim Überprüfen des Tokens:', error);
41+
console.error('Error while checking token:', error);
4342
throw error;
4443
}
4544
};
@@ -49,7 +48,7 @@ const AuthProvider: React.FC<AuthProviderProps> = ({ config, children }) => {
4948
try {
5049
return await authService.login(email, password, deviceName);
5150
} catch (error) {
52-
console.error('Fehler beim Einloggen:', error);
51+
console.error('Error during login:', error);
5352
throw error;
5453
}
5554
};
@@ -62,7 +61,7 @@ const AuthProvider: React.FC<AuthProviderProps> = ({ config, children }) => {
6261
return fetchedUser;
6362
});
6463
} catch (error) {
65-
console.error('Fehler beim Abrufen des Benutzers:', error);
64+
console.error('Error while fetching user:', error);
6665
throw error;
6766
}
6867
};
@@ -77,7 +76,7 @@ const AuthProvider: React.FC<AuthProviderProps> = ({ config, children }) => {
7776
return apiToken;
7877
})
7978
.catch((error) => {
80-
console.error('Fehler beim Abrufen des Tokens:', error);
79+
console.error('Error while getting token:', error);
8180
throw error;
8281
})
8382
.finally(() => {
@@ -90,7 +89,7 @@ const AuthProvider: React.FC<AuthProviderProps> = ({ config, children }) => {
9089
try {
9190
return await authService.logout();
9291
} catch (error) {
93-
console.error('Fehler beim Ausloggen:', error);
92+
console.error('Error during logout:', error);
9493
throw error;
9594
}
9695
};

src/interfaces/AuthConfig.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ export interface AuthConfig {
22
loginUrl: string;
33
logoutUrl: string;
44
userUrl: string;
5+
csrfTokenUrl?: string | null;
56
}

src/services/AuthService.ts

Lines changed: 71 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { AuthConfig, User } from 'react-native-laravel-sanctum';
33

44
class AuthService {
55
private readonly config: AuthConfig | null;
6+
private csrfToken: string | null = null; // CSRF-Token speichern
67

78
constructor(authConfig: AuthConfig) {
89
if (authConfig === null) {
@@ -11,27 +12,75 @@ class AuthService {
1112
this.config = authConfig;
1213
}
1314

14-
private async handleResponse(response: Response) {
15+
private async handleResponse(response: Response): Promise<void> {
1516
if (!response.ok) {
16-
throw new Error('The request was not successful');
17+
throw new Error('Request was not successful');
1718
}
1819
}
1920

21+
private async fetchCSRFToken() {
22+
try {
23+
if (!this.config || !this.config.csrfTokenUrl) {
24+
return;
25+
}
26+
27+
const response = await fetch(this.config.csrfTokenUrl, {
28+
method: 'GET',
29+
headers: {
30+
'Content-Type': 'application/json',
31+
},
32+
});
33+
34+
await this.handleResponse(response);
35+
36+
// Extrahieren des CSRF-Tokens aus dem Set-Cookie-Header
37+
const setCookieHeader = response.headers.get('set-cookie');
38+
if (setCookieHeader) {
39+
const csrfTokenMatch = setCookieHeader.match(/XSRF-TOKEN=([^;]*)/);
40+
if (csrfTokenMatch) {
41+
this.csrfToken = csrfTokenMatch[1] ?? null;
42+
}
43+
}
44+
} catch (error) {
45+
console.error('Error while fetching CSRF token:', error);
46+
throw error;
47+
}
48+
}
49+
50+
private async getRequestHeaders() {
51+
const headers: Record<string, string> = {
52+
'Content-Type': 'application/json',
53+
};
54+
55+
if (this.csrfToken) {
56+
headers['X-XSRF-TOKEN'] = this.csrfToken;
57+
}
58+
59+
const currentToken = await TokenStorage.getToken();
60+
if (currentToken) {
61+
headers.Authorization = `Bearer ${currentToken}`;
62+
}
63+
64+
return headers;
65+
}
66+
2067
async login(
2168
email: string,
2269
password: string,
2370
deviceName: string
2471
): Promise<boolean> {
2572
try {
2673
if (!this.config) {
27-
throw new Error('AuthConfig is null');
74+
throw new Error('Authentication configuration is missing');
75+
}
76+
77+
if (this.config.csrfTokenUrl) {
78+
await this.fetchCSRFToken();
2879
}
2980

3081
const response = await fetch(this.config.loginUrl, {
3182
method: 'POST',
32-
headers: {
33-
'Content-Type': 'application/json',
34-
},
83+
headers: await this.getRequestHeaders(),
3584
body: JSON.stringify({
3685
email,
3786
password,
@@ -51,15 +100,19 @@ class AuthService {
51100
return false;
52101
}
53102
} catch (error) {
54-
console.error('Fehler beim Einloggen:', error);
103+
console.error('Error during login:', error);
55104
throw error;
56105
}
57106
}
58107

59108
async logout(): Promise<boolean> {
60109
try {
61110
if (!this.config) {
62-
throw new Error('AuthConfig is null');
111+
throw new Error('Authentication configuration is missing');
112+
}
113+
114+
if (this.config.csrfTokenUrl) {
115+
await this.fetchCSRFToken();
63116
}
64117

65118
const currentToken = await TokenStorage.getToken();
@@ -70,25 +123,22 @@ class AuthService {
70123

71124
const response = await fetch(this.config.logoutUrl, {
72125
method: 'POST',
73-
headers: {
74-
'Content-Type': 'application/json',
75-
'Authorization': `Bearer ${currentToken}`,
76-
},
126+
headers: await this.getRequestHeaders(),
77127
});
78128

79129
await this.handleResponse(response);
80130
await TokenStorage.removeToken();
81131
return true;
82132
} catch (error) {
83-
console.error('Fehler beim Ausloggen:', error);
133+
console.error('Error during logout:', error);
84134
throw error;
85135
}
86136
}
87137

88138
async getUser(): Promise<User | null> {
89139
try {
90140
if (!this.config) {
91-
throw new Error('AuthConfig is null');
141+
throw new Error('Authentication configuration is missing');
92142
}
93143

94144
const currentToken = await TokenStorage.getToken();
@@ -97,25 +147,27 @@ class AuthService {
97147
return null;
98148
}
99149

150+
if (this.config.csrfTokenUrl) {
151+
await this.fetchCSRFToken();
152+
}
153+
100154
const response = await fetch(this.config.userUrl, {
101155
method: 'GET',
102-
headers: {
103-
'Content-Type': 'application/json',
104-
'Authorization': `Bearer ${currentToken}`,
105-
},
156+
headers: await this.getRequestHeaders(),
106157
});
107158

108159
await this.handleResponse(response);
109160

110161
const user = await response.json();
111162

112163
if (user) {
164+
this.csrfToken = null;
113165
return user;
114166
} else {
115167
return null;
116168
}
117169
} catch (error) {
118-
console.error('Fehler beim Abrufen des Benutzers:', error);
170+
console.error('Error while fetching user:', error);
119171
throw error;
120172
}
121173
}

src/utils/TokenStorage.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ class TokenStorage {
77
try {
88
await SecureStore.setItemAsync(TokenStorage.TOKEN_KEY, token);
99
} catch (error) {
10-
console.error('Fehler beim Speichern des verschlüsselten Tokens:', error);
10+
console.error('Error while saving the encrypted token:', error);
1111
throw error;
1212
}
1313
}
@@ -19,7 +19,7 @@ class TokenStorage {
1919
);
2020
return encryptedToken || null;
2121
} catch (error) {
22-
console.error('Fehler beim Abrufen des verschlüsselten Tokens:', error);
22+
console.error('Error while retrieving the encrypted token:', error);
2323
throw error;
2424
}
2525
}
@@ -28,7 +28,7 @@ class TokenStorage {
2828
try {
2929
await SecureStore.deleteItemAsync(TokenStorage.TOKEN_KEY);
3030
} catch (error) {
31-
console.error('Fehler beim Entfernen des verschlüsselten Tokens:', error);
31+
console.error('Error while removing the encrypted token:', error);
3232
throw error;
3333
}
3434
}

0 commit comments

Comments
 (0)