Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zitadel #15

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
13 changes: 13 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@angular/router": "^17.2.0",
"@angular/ssr": "^17.2.3",
"@netlify/functions": "^2.6.0",
"angular-oauth2-oidc": "^17.0.2",
"buffer": "^6.0.3",
"chart.js": "^4.3.0",
"express": "^4.19.2",
Expand Down
14 changes: 14 additions & 0 deletions src/app/app.config.browser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { mergeApplicationConfig, ApplicationConfig } from '@angular/core';
import { appConfig } from './app.config';
import { OAuthStorage } from 'angular-oauth2-oidc';

const browserConfig: ApplicationConfig = {
providers: [
{
provide: OAuthStorage,
useValue: localStorage,
}
]
};

export const config = mergeApplicationConfig(appConfig, browserConfig);
34 changes: 34 additions & 0 deletions src/app/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,27 @@ import { provideClientHydration } from '@angular/platform-browser';
import { provideHttpClient, withFetch } from '@angular/common/http';
import { ArrowDownNarrowWide, ArrowDownWideNarrow, BookText, Box, Check, ChevronDown, ChevronLeft, ChevronRight, Codesandbox, Cpu, Database, DollarSign, Facebook, Github, Home, Hotel, Linkedin, LucideAngularModule, MemoryStick, PcCase, Search, Server, SquareKanban, Twitter, User, Building2, Heater, CandlestickChart, MapPinned, Scale, Ellipsis, Menu, Leaf, ShoppingCart, ChevronUp, ExternalLink, Info } from 'lucide-angular';
import { MarkdownModule } from 'ngx-markdown';
import { AuthConfig, OAuthModule } from 'angular-oauth2-oidc';
import { provideCharts, withDefaultRegisterables } from 'ng2-charts';

const ZITADEL_CLIENT_ID = import.meta.env['NG_APP_ZITADEL_CLIENT_ID'];
const ZITADEL_DOMAIN = import.meta.env['NG_APP_ZITADEL_DOMAIN'];
const ZITADEL_USERINFO_ENDPOINT = import.meta.env['NG_APP_ZITADEL_USERINFO_ENDPOINT'];
Palabola marked this conversation as resolved.
Show resolved Hide resolved
const DOMAIN_BASE_URL = import.meta.env['NG_APP_DOMAIN_BASE_URL'];

const authConfig: AuthConfig = {
scope: 'openid profile email offline_access',
responseType: 'code',
oidc: true,
clientId: ZITADEL_CLIENT_ID,
issuer: ZITADEL_DOMAIN,
redirectUri: `${DOMAIN_BASE_URL}auth/callback`,
postLogoutRedirectUri: `${DOMAIN_BASE_URL}`,
requireHttps: false, // required for running locally
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure requireHttps is set to true in production to enhance security by enforcing HTTPS.

tokenEndpoint: `${ZITADEL_DOMAIN}/oauth/v2/token`,
userinfoEndpoint: ZITADEL_USERINFO_ENDPOINT,
};
Comment on lines +12 to +28
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Document the OAuth configuration settings in the README.md to ensure they are easily understandable and maintainable.


export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
Expand Down Expand Up @@ -55,6 +74,21 @@ export const appConfig: ApplicationConfig = {
}),
),
importProvidersFrom(MarkdownModule.forRoot()),
importProvidersFrom(
OAuthModule.forRoot({
resourceServer: {
allowedUrls: [
`${ZITADEL_DOMAIN}/admin/v1`,
`${ZITADEL_DOMAIN}/management/v1`,
`${ZITADEL_DOMAIN}/auth/v1/`],
sendAccessToken: true,
},
})
),
{
provide: AuthConfig,
useValue: authConfig,
}
],

};
5 changes: 5 additions & 0 deletions src/app/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,10 @@ export const routes: Routes = [
{ path: 'legal/tos', loadComponent: () => import('./pages/tos/tos.component').then(m => m.TOSComponent)},
{ path: 'datacenters', loadComponent: () => import('./pages/datacenters/datacenters.component').then(m => m.DatacentersComponent)},
{ path: 'vendors', loadComponent: () => import('./pages/vendors/vendors.component').then(m => m.VendorsComponent)},

{ path: 'auth/callback', loadComponent: () => import('./auth/callback/callback.component').then(m => m.CallbackComponent)},

{ path: 'dashboard', loadComponent: () => import('./pages/my-spare-cores/my-spare-cores.component').then(m => m.MySpareCoresComponent)},

{ path: '**', redirectTo: '' }
];
4 changes: 4 additions & 0 deletions src/app/auth/callback/callback.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<div class="w-full">
<div class="content_section">
</div>
</div>
7 changes: 7 additions & 0 deletions src/app/auth/callback/callback.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.content_section {
@apply bg-primary;
@apply text-white;

padding: 4rem 2rem;
height: 100vh;
}
23 changes: 23 additions & 0 deletions src/app/auth/callback/callback.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { CallbackComponent } from './callback.component';

describe('CallbackComponent', () => {
let component: CallbackComponent;
let fixture: ComponentFixture<CallbackComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [CallbackComponent]
})
.compileComponents();

fixture = TestBed.createComponent(CallbackComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
Palabola marked this conversation as resolved.
Show resolved Hide resolved
});
41 changes: 41 additions & 0 deletions src/app/auth/callback/callback.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Component, Inject, PLATFORM_ID } from '@angular/core';
import { AuthenticationService } from '../../services/authentication.service';
import { Router, RouterModule } from '@angular/router';
import { isPlatformBrowser } from '@angular/common';

@Component({
selector: 'app-callback',
standalone: true,
imports: [RouterModule],
templateUrl: './callback.component.html',
styleUrl: './callback.component.scss'
})
export class CallbackComponent {

constructor(
@Inject(PLATFORM_ID) private platformId: object,
private authService: AuthenticationService,
private router: Router
) { }

ngOnInit() {

if(isPlatformBrowser(this.platformId)) {
this.authService.loginCodeFlow().then(() => {

let token = this.authService.getToken();
console.log('token', token);
let url = sessionStorage.getItem('prelogin_url') || '/';
sessionStorage.removeItem('prelogin_url');
this.router.navigateByUrl(url);
/*
this.authService.getOIDCUser().subscribe(user => {
console.log('user', user);
});
*/
});
}

}

}
16 changes: 12 additions & 4 deletions src/app/layout/header/header.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,22 @@
name="menu" >
</lucide-icon>
</li>
<!--
<li>
<button class="login_button text-sm items-center">
<li *ngIf="!isLoggedIn() || true">
<button
class="login_button text-sm items-center"
(click)="login()">
<lucide-icon name="user" class="h-4 w-4 mr-1"></lucide-icon>
Log in
</button>
</li>
-->
<li *ngIf="isLoggedIn() || true">
<button
class="login_button text-sm items-center"
(click)="logout()">
<lucide-icon name="user" class="h-4 w-4 mr-1"></lucide-icon>
Log out
</button>
</li>
</ul>
</div>
</div>
Expand Down
23 changes: 21 additions & 2 deletions src/app/layout/header/header.component.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,33 @@
import { Component } from '@angular/core';
import { RouterLink } from '@angular/router';
import { LucideAngularModule } from 'lucide-angular';
import { AuthenticationService } from '../../services/authentication.service';
import { CommonModule } from '@angular/common';
Comment on lines 3 to +5
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review the import usage as they are only used as types.

Consider using TypeScript's import type to explicitly indicate that these imports are only used for type checking. This can help with clarity and potentially optimize bundling processes.

- import { AuthenticationService } from '../../services/authentication.service';
- import { CommonModule } from '@angular/common';
+ import type { AuthenticationService } from '../../services/authentication.service';
+ import type { CommonModule } from '@angular/common';

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
import { LucideAngularModule } from 'lucide-angular';
import { AuthenticationService } from '../../services/authentication.service';
import { CommonModule } from '@angular/common';
import { LucideAngularModule } from 'lucide-angular';
import type { AuthenticationService } from '../../services/authentication.service';
import type { CommonModule } from '@angular/common';


@Component({
selector: 'app-header',
standalone: true,
imports: [LucideAngularModule, RouterLink],
imports: [LucideAngularModule, RouterLink, CommonModule],
templateUrl: './header.component.html',
styleUrl: './header.component.scss'
styleUrl: './header.component.scss',
host: {ngSkipHydration: 'true'},
})
export class HeaderComponent {

constructor(
private authService: AuthenticationService
) { }

isLoggedIn() {
return this.authService.isLoggedIn();
}

login() {
this.authService.authenticate();
}
Palabola marked this conversation as resolved.
Show resolved Hide resolved

logout() {
this.authService.signout();
}

}
16 changes: 16 additions & 0 deletions src/app/services/authentication.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';

import { AuthenticationService } from './authentication.service';

describe('AuthenticationService', () => {
let service: AuthenticationService;

beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(AuthenticationService);
});

it('should be created', () => {
expect(service).toBeTruthy();
});
});
67 changes: 67 additions & 0 deletions src/app/services/authentication.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { Injectable } from '@angular/core';
import { AuthConfig, OAuthEvent, OAuthService } from 'angular-oauth2-oidc';
Comment on lines +1 to +2
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using type-only imports for Angular and RxJS modules.

- import { Injectable } from '@angular/core';
- import { AuthConfig, OAuthEvent, OAuthService } from 'angular-oauth2-oidc';
- import { BehaviorSubject } from 'rxjs';
+ import type { Injectable } from '@angular/core';
+ import type { AuthConfig, OAuthEvent, OAuthService } from 'angular-oauth2-oidc';
+ import type { BehaviorSubject } from 'rxjs';

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
import { Injectable } from '@angular/core';
import { AuthConfig, OAuthEvent, OAuthService } from 'angular-oauth2-oidc';
import type { Injectable } from '@angular/core';
import type { AuthConfig, OAuthEvent, OAuthService } from 'angular-oauth2-oidc';
import type { BehaviorSubject } from 'rxjs';

import { BehaviorSubject, from, Observable } from 'rxjs';

@Injectable({
providedIn: 'root',
})
export class AuthenticationService {

authedState = new BehaviorSubject<boolean | undefined>(undefined);

constructor(
private oauthService: OAuthService,
private authConfig: AuthConfig,
) {
this.oauthService.events.subscribe((event: OAuthEvent) => {
console.log('oauth event', event);
Palabola marked this conversation as resolved.
Show resolved Hide resolved
switch (event.type) {
case 'logout':
this.authedState.next(false);
break;
}
});
}

public getOIDCUser(): Observable<any> {
Palabola marked this conversation as resolved.
Show resolved Hide resolved
return from(this.oauthService.loadUserProfile());
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Specify a more precise return type than any for getOIDCUser to enhance type safety and code maintainability.

- public getOIDCUser(): Observable<any> {
+ public getOIDCUser(): Observable<UserProfile> { // Assuming UserProfile is the correct type

Committable suggestion was skipped due low confidence.


public async authenticate(): Promise<void> {
this.oauthService.configure(this.authConfig);
this.oauthService.setupAutomaticSilentRefresh();

this.oauthService.strictDiscoveryDocumentValidation = false;
await this.oauthService.loadDiscoveryDocumentAndTryLogin();


if (!this.oauthService.hasValidIdToken()) {
const newState = window.location.pathname;
sessionStorage.setItem('prelogin_url', newState);
this.oauthService.initImplicitFlow();
}

return;
}

public async loginCodeFlow(): Promise<void> {
return this.oauthService.initCodeFlow();
}

public async getToken(): Promise<string> {
return this.oauthService.getIdToken();
}

public async getAccessToken(): Promise<string> {
return this.oauthService.getAccessToken();
}

public isLoggedIn(): boolean {
console.log('hasValidAccessToken', this.oauthService.hasValidAccessToken());
Palabola marked this conversation as resolved.
Show resolved Hide resolved
return this.oauthService.hasValidAccessToken();
}

public signout(): void {
this.oauthService.logOut();
}
}
4 changes: 2 additions & 2 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { appConfig } from './app/app.config';
import { config } from './app/app.config.browser';
Palabola marked this conversation as resolved.
Show resolved Hide resolved


bootstrapApplication(AppComponent, appConfig)
bootstrapApplication(AppComponent, config)
.catch((err) => console.error(err));
Loading