Skip to content

Commit

Permalink
fix(*): status codes returning from backend after registration (#80)
Browse files Browse the repository at this point in the history
Backend returning status code 500 after a successful registration
  • Loading branch information
Kif-Fando authored Sep 29, 2021
1 parent 22d6094 commit ad8db61
Show file tree
Hide file tree
Showing 8 changed files with 131 additions and 37 deletions.
2 changes: 1 addition & 1 deletion public/src/api/httpClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export function postSubscriptions(email: string): Promise<any> {

export function postUser(data: RegistrationUser): Promise<any> {
return makeApiRequest({
url: ApiUrl.Users,
url: `${ApiUrl.Users}/${data.op}`,
method: 'post',
data
});
Expand Down
33 changes: 21 additions & 12 deletions public/src/api/makeApiRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,27 @@ export function makeApiRequest<T>(
return response.data;
})
.catch((error) => {
if (error.response.status === 401) {
sessionStorage.removeItem('email');
sessionStorage.removeItem('token');
return {
...error,
errorText:
'Authentication failed, please check your credentials and try again'
};
switch (error.response.status) {
case 401:
sessionStorage.removeItem('email');
sessionStorage.removeItem('token');
return {
...error,
errorText:
'Authentication failed, please check your credentials and try again'
};
break;
case 409:
return {
...error,
errorText: 'User already exists'
};
break;
default:
return {
...error,
errorText: 'Something went wrong. Please try again later'
};
}
return {
...error,
errorText: 'Something went wrong. Please try again later'
};
});
}
1 change: 1 addition & 0 deletions public/src/interfaces/User.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,5 @@ export interface RegistrationUser {
lastName: string;
firstName: string;
password?: string;
op?: LoginFormMode;
}
4 changes: 0 additions & 4 deletions public/src/pages/auth/Login/Login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,6 @@ export const Login: FC = () => {
const { value } = target as HTMLSelectElement & { value: LoginFormMode };
setForm({ ...form, op: value });
setMode(value);
switch (value as LoginFormMode) {
default:
return;
}
};

const sendUser = (e: FormEvent) => {
Expand Down
38 changes: 34 additions & 4 deletions public/src/pages/auth/Register/Register.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { FC, FormEvent, useState } from 'react';
import { postUser } from '../../../api/httpClient';
import { RegistrationUser } from '../../../interfaces/User';
import { RegistrationUser, LoginFormMode } from '../../../interfaces/User';
import AuthLayout from '../AuthLayout';
import { Link } from 'react-router-dom';
import showRegResponse from './showRegReponse';
Expand All @@ -9,30 +9,60 @@ const defaultUser: RegistrationUser = {
email: '',
firstName: '',
lastName: '',
password: ''
password: '',
op: LoginFormMode.BASIC
};

export const Register: FC = () => {
const [form, setForm] = useState<RegistrationUser>(defaultUser);
const { email, firstName, lastName, password } = form;

const [regResponse, setRegResponse] = useState<RegistrationUser | null>();
const [errorText, setErrorText] = useState<string | null>();

const [authMode, setAuthMode] = useState<LoginFormMode>(LoginFormMode.BASIC);

const onInput = ({ target }: { target: EventTarget | null }) => {
const { name, value } = target as HTMLInputElement;
setForm({ ...form, [name]: value });
};

const onAuthModeChange = ({ target }: { target: EventTarget | null }) => {
const { value } = target as HTMLSelectElement & { value: LoginFormMode };
setForm({ ...form, op: value });
setAuthMode(value);
};

const sendUser = (e: FormEvent) => {
e.preventDefault();

postUser(form).then((data) => setRegResponse(data));
postUser(form).then((data) => {
setRegResponse(data);
setErrorText(data.errorText);
});
};

return (
<AuthLayout>
<div className="login-form">
<form onSubmit={sendUser}>
<div className="form-group">
<label>Registration Type</label>
<select
className="form-control"
name="op"
placeholder="Authentication Type"
value={authMode}
onChange={onAuthModeChange}
>
<option value={LoginFormMode.BASIC}>
Simple REST-based Registration
</option>
<option value={LoginFormMode.OIDC}>
Simple OIDC-based Registration
</option>
</select>
</div>
<div className="form-group">
<label>First name</label>
<input
Expand Down Expand Up @@ -68,7 +98,7 @@ export const Register: FC = () => {
onInput={onInput}
/>
</div>

{errorText && <div className="error-text">{errorText}</div>}
<div className="form-group">
<label>Password</label>
<input
Expand Down
32 changes: 29 additions & 3 deletions src/keycloak/keycloak.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import * as jwkToPem from 'jwk-to-pem';
import { JWK } from 'jwk-to-pem';
import { stringify } from 'querystring';
import { verify } from 'jsonwebtoken';
import { User } from 'src/model/user.entity';

export interface OIDCIdentityConfig {
issuer?: string;
Expand All @@ -28,6 +29,10 @@ export interface RegisterUserData {
password: string;
}

export interface ExistingUserData {
email: string,
}

export interface GenerateTokenData {
username: string;
password: string;
Expand Down Expand Up @@ -137,17 +142,37 @@ export class KeyCloakService implements OnModuleInit {
});
}

public async isUserExists({
email,
}: ExistingUserData): Promise<Boolean> {
this.log.debug(`Called isUserExist`);

const { access_token, token_type } = await this.generateToken();

const [existingUser] = await this.httpClient.get(
`${this.server_uri}/admin/realms/${this.realm}/users?email=${email}`,
{
headers: {
'Content-Type': 'application/json',
Authorization: `${token_type} ${access_token}`,
},
responseType: 'json',
}
);
return !!existingUser;
}

public async registerUser({
firstName,
lastName,
email,
password,
}: RegisterUserData): Promise<void> {
}: RegisterUserData): Promise<User> {
this.log.debug(`Called registerUser`);

const { access_token, token_type } = await this.generateToken();

await this.httpClient.post(
const user: User = await this.httpClient.post(
`${this.server_uri}/admin/realms/${this.realm}/users`,
{
firstName,
Expand All @@ -170,7 +195,8 @@ export class KeyCloakService implements OnModuleInit {
},
responseType: 'json',
},
);
)
return user;
}

public async generateToken(tokenData?: GenerateTokenData): Promise<Token> {
Expand Down
1 change: 1 addition & 0 deletions src/users/api/CreateUserRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ import { UserDto } from './UserDto';
export class CreateUserRequest extends UserDto {
@ApiProperty()
password: string;
op: string;
}
57 changes: 44 additions & 13 deletions src/users/users.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
Controller,
Get,
Header,
HttpException,
HttpStatus,
InternalServerErrorException,
Logger,
Expand Down Expand Up @@ -153,7 +154,7 @@ export class UsersController {
return users.map<UserDto>(UserDto.convertToApi);
}

@Post()
@Post('/basic')
@ApiOperation({
description: 'creates user',
})
Expand All @@ -163,8 +164,14 @@ export class UsersController {
})
async createUser(@Body() user: CreateUserRequest): Promise<UserDto> {
try {
this.logger.debug(`Create a user: ${user}`);

this.logger.debug(`Create a basic user: ${user}`);
const userExists = await this.usersService.findByEmail(user.email);
if (userExists) {
throw new HttpException(
'User already exists',
409
)
}
const newUser = UserDto.convertToApi(
await this.usersService.createUser(
user.email,
Expand All @@ -173,20 +180,44 @@ export class UsersController {
user.password,
),
);
return newUser;
} catch (err) {
throw new HttpException(err.message ?? 'Something went wrong', err.status ?? 500)
}
}

@Post('/oidc')
@ApiOperation({
description: 'creates user',
})
@ApiResponse({
type: UserDto,
status: 200,
})
async createOIDCUser(@Body() user: CreateUserRequest): Promise<object | string> {
try {
this.logger.debug(`Create a OIDC user: ${user}`);

await this.keyCloakService.registerUser({
const userExists = await this.keyCloakService.isUserExists({
email: user.email,
firstName: user.firstName,
lastName: user.lastName,
password: user.password,
});

if (userExists) {
throw new HttpException(
'User already exists',
409
)
}
const newUser = UserDto.convertToApi(
await this.keyCloakService.registerUser({
email: user.email,
firstName: user.firstName,
lastName: user.lastName,
password: user.password,
}));
return newUser;
} catch (err) {
throw new InternalServerErrorException({
error: err.message,
location: __filename,
});

} catch ({ response = 'Something went wrong', status = 500 }) {
throw new HttpException(response, status)
}
}

Expand Down

0 comments on commit ad8db61

Please sign in to comment.