feat: implement Google OAuth2 authentication flow
Some checks failed
CI / Get Changed Files (pull_request) Successful in 8s
CI / eslint (pull_request) Successful in 33s
CI / prettier (pull_request) Failing after 36s
CI / oxlint (pull_request) Successful in 42s
CI / Checkstyle Main (pull_request) Failing after 1m8s
CI / Docker frontend validation (pull_request) Successful in 1m46s
CI / test-build (pull_request) Successful in 1m46s
CI / Docker backend validation (pull_request) Successful in 2m36s
Some checks failed
CI / Get Changed Files (pull_request) Successful in 8s
CI / eslint (pull_request) Successful in 33s
CI / prettier (pull_request) Failing after 36s
CI / oxlint (pull_request) Successful in 42s
CI / Checkstyle Main (pull_request) Failing after 1m8s
CI / Docker frontend validation (pull_request) Successful in 1m46s
CI / test-build (pull_request) Successful in 1m46s
CI / Docker backend validation (pull_request) Successful in 2m36s
This commit is contained in:
parent
c9632d6b26
commit
07b594fa36
11 changed files with 342 additions and 18 deletions
|
@ -39,6 +39,15 @@ export const routes: Routes = [
|
|||
import('./feature/auth/oauth2/oauth2-callback.component').then(
|
||||
(m) => m.OAuth2CallbackComponent
|
||||
),
|
||||
data: { provider: 'github' }
|
||||
},
|
||||
{
|
||||
path: 'oauth2/callback/google',
|
||||
loadComponent: () =>
|
||||
import('./feature/auth/oauth2/oauth2-callback.component').then(
|
||||
(m) => m.OAuth2CallbackComponent
|
||||
),
|
||||
data: { provider: 'google' }
|
||||
},
|
||||
{
|
||||
path: 'game/blackjack',
|
||||
|
|
|
@ -89,7 +89,7 @@
|
|||
<div class="flex-grow h-px bg-deep-blue-light/30"></div>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<div class="space-y-3 mb-4">
|
||||
<button
|
||||
(click)="loginWithGithub()"
|
||||
class="w-full py-2.5 px-4 rounded flex items-center justify-center bg-gray-800 hover:bg-gray-700 text-white transition-colors"
|
||||
|
@ -106,6 +106,35 @@
|
|||
</svg>
|
||||
Mit GitHub anmelden
|
||||
</button>
|
||||
|
||||
<button
|
||||
(click)="loginWithGoogle()"
|
||||
class="w-full py-2.5 px-4 rounded flex items-center justify-center bg-white hover:bg-gray-100 text-gray-800 transition-colors"
|
||||
>
|
||||
<svg
|
||||
class="h-5 w-5 mr-2"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fill="#EA4335"
|
||||
d="M5.266 9.765A7.077 7.077 0 0 1 12 4.909c1.69 0 3.218.6 4.418 1.582L19.91 3C17.782 1.145 15.055 0 12 0 7.27 0 3.198 2.698 1.24 6.65l4.026 3.115Z"
|
||||
/>
|
||||
<path
|
||||
fill="#34A853"
|
||||
d="M16.04 18.013c-1.09.703-2.474 1.078-4.04 1.078a7.077 7.077 0 0 1-6.723-4.823l-4.04 3.067A11.965 11.965 0 0 0 12 24c2.933 0 5.735-1.043 7.834-3l-3.793-2.987Z"
|
||||
/>
|
||||
<path
|
||||
fill="#4A90E2"
|
||||
d="M19.834 21c2.195-2.048 3.62-5.096 3.62-9 0-.71-.109-1.473-.272-2.182H12v4.637h6.436c-.317 1.559-1.17 2.766-2.395 3.558L19.834 21Z"
|
||||
/>
|
||||
<path
|
||||
fill="#FBBC05"
|
||||
d="M5.277 14.268A7.12 7.12 0 0 1 4.909 12c0-.782.125-1.533.357-2.235L1.24 6.65A11.934 11.934 0 0 0 0 12c0 1.92.445 3.73 1.237 5.335l4.04-3.067Z"
|
||||
/>
|
||||
</svg>
|
||||
Mit Google anmelden
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="text-center">
|
||||
|
|
|
@ -71,6 +71,11 @@ export class LoginComponent {
|
|||
window.location.href = `${environment.apiUrl}/oauth2/github/authorize`;
|
||||
}
|
||||
|
||||
loginWithGoogle(): void {
|
||||
this.isLoading.set(true);
|
||||
window.location.href = `${environment.apiUrl}/oauth2/google/authorize`;
|
||||
}
|
||||
|
||||
switchToForgotPassword() {
|
||||
this.forgotPassword.emit();
|
||||
}
|
||||
|
|
|
@ -32,25 +32,46 @@ export class OAuth2CallbackComponent implements OnInit {
|
|||
// Check for code in URL params
|
||||
this.route.queryParams.subscribe((params) => {
|
||||
const code = params['code'];
|
||||
const provider = this.route.snapshot.data['provider'] || 'github';
|
||||
|
||||
if (code) {
|
||||
// Exchange GitHub code for a JWT token
|
||||
this.authService.githubAuth(code).subscribe({
|
||||
next: () => {
|
||||
// Redirect to home after successful authentication
|
||||
this.router.navigate(['/home']);
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('GitHub authentication error:', err);
|
||||
this.error = err.error?.message || 'Authentication failed. Please try again.';
|
||||
console.log('Error details:', err);
|
||||
if (provider === 'google') {
|
||||
// Exchange Google code for a JWT token
|
||||
this.authService.googleAuth(code).subscribe({
|
||||
next: () => {
|
||||
// Redirect to home after successful authentication
|
||||
this.router.navigate(['/home']);
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('Google authentication error:', err);
|
||||
this.error = err.error?.message || 'Authentication failed. Please try again.';
|
||||
console.log('Error details:', err);
|
||||
|
||||
// Redirect back to landing page after showing error
|
||||
setTimeout(() => {
|
||||
this.router.navigate(['/']);
|
||||
}, 3000);
|
||||
},
|
||||
});
|
||||
// Redirect back to landing page after showing error
|
||||
setTimeout(() => {
|
||||
this.router.navigate(['/']);
|
||||
}, 3000);
|
||||
},
|
||||
});
|
||||
} else {
|
||||
// Exchange GitHub code for a JWT token
|
||||
this.authService.githubAuth(code).subscribe({
|
||||
next: () => {
|
||||
// Redirect to home after successful authentication
|
||||
this.router.navigate(['/home']);
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('GitHub authentication error:', err);
|
||||
this.error = err.error?.message || 'Authentication failed. Please try again.';
|
||||
console.log('Error details:', err);
|
||||
|
||||
// Redirect back to landing page after showing error
|
||||
setTimeout(() => {
|
||||
this.router.navigate(['/']);
|
||||
}, 3000);
|
||||
},
|
||||
});
|
||||
}
|
||||
} else {
|
||||
this.error = 'Authentication failed. No authorization code received.';
|
||||
|
||||
|
|
|
@ -79,6 +79,15 @@ export class AuthService {
|
|||
);
|
||||
}
|
||||
|
||||
googleAuth(code: string): Observable<AuthResponse> {
|
||||
return this.http.post<AuthResponse>(`${this.oauthUrl}/google/callback`, { code }).pipe(
|
||||
tap((response) => {
|
||||
this.setToken(response.token);
|
||||
this.loadCurrentUser();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
logout(): void {
|
||||
localStorage.removeItem(TOKEN_KEY);
|
||||
localStorage.removeItem(USER_KEY);
|
||||
|
|
Reference in a new issue