⚠️ Malware / Trojaner / VirenGuardBreaker: Derailing AI-assisted malware analysis with a code comment(10.09.2026 um 11:00 Uhr)
⚠️ Malware / Trojaner / VirenAttack hides malware in PNGs and drops custom reverse tunnel on victims' machines(31.08.2026 um 20:26 Uhr)
⚠️ Malware / Trojaner / Viren33-hour BGP hijack of Softaculous traffic prompts security scramble(01.09.2026 um 14:04 Uhr)
🕵️ SicherheitslückenProlific Microsoft 0-day hunter drops CrowdStrike Falcon exploit PoC(03.09.2026 um 20:08 Uhr)
🔧 AI Nachrichten OpenAI commits $1B in AI credits to frontline cyber defenders(04.09.2026 um 01:47 Uhr)
⚠️ Malware / Trojaner / VirenGuardBreaker: Derailing AI-assisted malware analysis with a code comment(10.09.2026 um 11:00 Uhr)
⚠️ Malware / Trojaner / VirenAttack hides malware in PNGs and drops custom reverse tunnel on victims' machines(31.08.2026 um 20:26 Uhr)
⚠️ Malware / Trojaner / Viren33-hour BGP hijack of Softaculous traffic prompts security scramble(01.09.2026 um 14:04 Uhr)
🕵️ SicherheitslückenProlific Microsoft 0-day hunter drops CrowdStrike Falcon exploit PoC(03.09.2026 um 20:08 Uhr)
🔧 AI Nachrichten OpenAI commits $1B in AI credits to frontline cyber defenders(04.09.2026 um 01:47 Uhr)

🔧 Programmierung 🕛 vor 1 Jahr 9 Min Lesezeit
0

OpenAPI and Frontend

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht




Recap



In the previous part of the series, we configured the PostgreSQL database, created the User entity, implemented JSON Web Tokens, and secured our API.



In this part, we will add two more methods in the backend for convenience and demonstration and then build the frontend application.






Logout & User Information



Before jumping to the frontend part, we should take one step ahead and think about how we will test everything without using the browser's Dev Tools. We authenticate users with cookies, and of course, we have to be able to remove them when they sign out, so we introduce the "logout" endpoint:




CODE
...

@PostMapping(value = "/logout")
public ResponseEntity<String> logout(
HttpServletResponse res
) {
CookiesResult result = this.authService.logout();

res.addCookie(result.getResult()[0]);
res.addCookie(result.getResult()[1]);
return ResponseEntity.status(HttpStatus.OK).build();
}






[AuthController.java]



The AuthService's method just passes the request down to the JwtService, where the logic, yet again, is quite simple. By returning cookies with the same parameters, i.e., name and path, but zeroed expiration time, we're essentially revoking them in the browser the moment it processes the response.




CODE
...

public @NonNull Cookie[] revokeCookies() {
return new Cookie[]{
this.createAuth("", 0),
this.createMarker("", 0)
};
}






[JwtServiceImpl.java]



As I said in the previous article, you should implement a revocation mechanism that blacklists tokens until they expire. But, since this is a demo application, we will only revoke cookies for anyone, even if they're not yet authenticated.



Next, to test that we have signed in successfully and everything is good and well, let's create an endpoint that returns the current user's information.




CODE
...

@GetMapping(value = "/", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<UserInfo> getUser() {
UserInfo user = this.accountService.getUser();
return ResponseEntity.status(HttpStatus.OK)
.body(user);
}






[AccountController.java]



And the corresponding service:




CODE
@Service
@RequiredArgsConstructor
public class AccountServiceImpl implements AccountService {

private final UserRepo userRepo;

public UserInfo getUser() {
String principal = (String) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
Optional<User> userOptional = this.userRepo.findFirstById(UUID.fromString(principal));
if (userOptional.isEmpty()) {
throw new RuntimeException("user_not_found");
}

User user = userOptional.get();
return new UserInfo(user.getUsername());
}
}






[AccountServiceImpl.java]



Note how we retrieve the principal (or, in JWT terms, the subject). When the HTTP request hits the application, it's passed through several mechanisms within Spring, as well as our JwtFilter we implemented earlier. It populates the context so we can retrieve this information across the app.






OpenAPI



Since we're done creating endpoints for all operations we need right now, let's add , and provide our app with the generated services coupled by a module.




CODE
providers: [
...
provideHttpClient(),
{ provide: API_ROOT_URL_TOKEN, useValue: environment.apiRootUrl },
importProvidersFrom(ApiModule),
]






[app.config.ts]






User Interface



Let's get to the most creative part of this series – the user interface, aka frontend.



We will start by outlining our navigation routes. Note that we don't add any router filters, so we can easily navigate between these pages during development.




CODE
export const appRoutes: Route[] = [
{ path: 'account', component: AccountComponent },
{ path: 'login', component: LoginComponent },
{ path: 'signup', component: SignupComponent },
{ path: '', pathMatch: 'full', redirectTo: 'login' },
];






[app.routes.ts]



Moving on to the signup page, start by creating an Angular reactive form. It has the same validation rules for the username field as the backend, so we can catch errors faster. Also, we won't even bother validating the "repeat_password" control, because we will check if it matches the password anyway.




CODE
public readonly form = this.fb.nonNullable.group({
username: this.fb.nonNullable.control<string>('', [Validators.required, Validators.pattern('[\\da-zA-Z_-]+')]),
password: this.fb.nonNullable.control<string>('', [Validators.required, Validators.minLength(6)]),
repeat_password: this.fb.nonNullable.control<string>('', [Validators.required]),
});






[signup.component.ts]



Next, we add some HTML to render this form. Not only will our forms be visually pleasing, but they will also be accessible. For the user's convenience, we will explicitly disable the spellcheck and automatic capitalization, even though we look users up in a case-insensitive manner.



Also, since the CSS code is provided in the repo, I will not mention it here at all. You're welcome to either re-use it or write your own from scratch.




CODE
<form [formGroup]="form" (ngSubmit)="submit()" class="c-form">
<div class="w-input">
<label for="username" class="f-label">Username</label>
<input
formControlName="username"
id="username"
type="text"
autocomplete="username"
autocapitalize="off"
autocorrect="off"
spellcheck="false"
class="f-input"
/>
</div>

...
</form>






[signup.component.ts]



Then, because we need some logic to be done before the data is sent, we will add a method to mark the form "dirty" if the validation fails and add an error message. It will then send the request and handle its response.




CODE
...

public submit(): void {
if (!this.form.valid) {
this.form.markAsDirty();
this.errors$.next('The form is invalid');
this.form.valueChanges.pipe(first()).subscribe(() => this.errors$.next(''));
return;
}

if (this.form.value.password !== this.form.value.repeat_password) {
this.errors$.next("Passwords don't match");
this.form.valueChanges.pipe(first()).subscribe(() => this.errors$.next(''));
return;
}

const formValue = this.form.getRawValue();

this.authService
.signup({ body: { username: formValue.username, password: formValue.password } })
.pipe(catchError(this.handleHttpError))
.subscribe({
next: () => this.router.navigate(['account']),
error: (code: string) => this.errors$.next(signupErrors[code] ?? signupErrors['_']),
});
}






[signup.component.ts]



For a seamless experience, let's add the navigation link that adds the username to the router state.




CODE
<div class="c-split">
<span class="text-split">Already have an account?</span>
<a routerLink="/login" [state]="{ username: form.value.username }" class="link-split">Sign in</a>
</div>






[signup.component.ts]



The login page looks very alike, so I'll skip ahead and add a method that pulls the username from the router state and applies it to the form:




CODE
...

public ngOnInit(): void {
const navUsername = this.router.lastSuccessfulNavigation?.extras?.state?.['username'];
if (navUsername) {
this.form.patchValue({ username: navUsername });
}
}






[login.component.ts]



How is it convenient? Easy: imagine yourself as a user who tried to sign up on a website and got a message that this user already exists. You will likely remember that some time ago you already signed up here, and when you click the "sign in" link, the login form will greet you with that username already in place. Same applies in the other direction.



So, what about those two endpoind we added at the beginning of this part? We will use them for the account page. Let's (try to) load some data when this page is opened:




CODE
...

public ngOnInit(): void {
this.loadData(this.accountService.getPublic(), this.responsePublic$);

this.accountService.getUser().subscribe({
next: (user) => this.userInfo$.next(user),
});
}






[account.component.ts]



And greet the user by their username, if they're signed in (remember, we don't have router filters):




CODE
@if (userInfo$ | async; as userInfo) {
<div class="c-title">
<h2 class="text-title">Hello, {{ userInfo.username }}</h2>
</div>
}






[account.component.ts]



That's it, you may now spin up everything and see how it works for yourself!




TODO: Add the drumroll sound.







Conclusion



In this part we've implemented a fully-functional accessible frontend based on auto-generated API models from the OpenAPI document.



As a reminder, all the code fragments in this article are in the on Unsplash

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
1 Quelle
GuardBreaker: Derailing AI-assisted malware analysis with a code comment
1 Quelle
Attack hides malware in PNGs and drops custom reverse tunnel on victims' machines
1 Quelle
33-hour BGP hijack of Softaculous traffic prompts security scramble
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten OpenAPI and Frontend

Thematisch verwandte Begriffe: OpenAPI, Frontend · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...