Compare commits

...

5 commits

Author SHA1 Message Date
Jonathan Jogenfors
69daa3804a Cleanup 2023-06-21 16:04:19 +02:00
Jonathan Jogenfors
9dabfe09d0 Add some docs 2023-06-21 15:41:21 +02:00
Jonathan Jogenfors
f89ae65d65 Generate api definition 2023-06-21 15:39:17 +02:00
Jonathan Jogenfors
1718ae1fe9 Merge branch 'main' into feat/access-token-endpoint 2023-06-21 14:59:35 +02:00
Jonathan Jogenfors
7327505ad7 Initial key login functionality 2023-06-21 14:53:17 +02:00
9 changed files with 271 additions and 0 deletions

View file

@ -115,6 +115,7 @@ Class | Method | HTTP request | Description
*AuthenticationApi* | [**adminSignUp**](doc//AuthenticationApi.md#adminsignup) | **POST** /auth/admin-sign-up |
*AuthenticationApi* | [**changePassword**](doc//AuthenticationApi.md#changepassword) | **POST** /auth/change-password |
*AuthenticationApi* | [**getAuthDevices**](doc//AuthenticationApi.md#getauthdevices) | **GET** /auth/devices |
*AuthenticationApi* | [**keyLogin**](doc//AuthenticationApi.md#keylogin) | **GET** /auth/keyLogin |
*AuthenticationApi* | [**login**](doc//AuthenticationApi.md#login) | **POST** /auth/login |
*AuthenticationApi* | [**logout**](doc//AuthenticationApi.md#logout) | **POST** /auth/logout |
*AuthenticationApi* | [**logoutAuthDevice**](doc//AuthenticationApi.md#logoutauthdevice) | **DELETE** /auth/devices/{id} |

View file

@ -12,6 +12,7 @@ Method | HTTP request | Description
[**adminSignUp**](AuthenticationApi.md#adminsignup) | **POST** /auth/admin-sign-up |
[**changePassword**](AuthenticationApi.md#changepassword) | **POST** /auth/change-password |
[**getAuthDevices**](AuthenticationApi.md#getauthdevices) | **GET** /auth/devices |
[**keyLogin**](AuthenticationApi.md#keylogin) | **GET** /auth/keyLogin |
[**login**](AuthenticationApi.md#login) | **POST** /auth/login |
[**logout**](AuthenticationApi.md#logout) | **POST** /auth/logout |
[**logoutAuthDevice**](AuthenticationApi.md#logoutauthdevice) | **DELETE** /auth/devices/{id} |
@ -166,6 +167,59 @@ This endpoint does not need any parameter.
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **keyLogin**
> LoginResponseDto keyLogin()
Get user login details and a bearer token from an API key
### Example
```dart
import 'package:openapi/api.dart';
// TODO Configure API key authorization: cookie
//defaultApiClient.getAuthentication<ApiKeyAuth>('cookie').apiKey = 'YOUR_API_KEY';
// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
//defaultApiClient.getAuthentication<ApiKeyAuth>('cookie').apiKeyPrefix = 'Bearer';
// TODO Configure API key authorization: api_key
//defaultApiClient.getAuthentication<ApiKeyAuth>('api_key').apiKey = 'YOUR_API_KEY';
// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
//defaultApiClient.getAuthentication<ApiKeyAuth>('api_key').apiKeyPrefix = 'Bearer';
// TODO Configure HTTP Bearer authorization: bearer
// Case 1. Use String Token
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken('YOUR_ACCESS_TOKEN');
// Case 2. Use Function which generate token.
// String yourTokenGeneratorFunction() { ... }
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken(yourTokenGeneratorFunction);
final api_instance = AuthenticationApi();
try {
final result = api_instance.keyLogin();
print(result);
} catch (e) {
print('Exception when calling AuthenticationApi->keyLogin: $e\n');
}
```
### Parameters
This endpoint does not need any parameter.
### Return type
[**LoginResponseDto**](LoginResponseDto.md)
### Authorization
[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer)
### HTTP request headers
- **Content-Type**: Not defined
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **login**
> LoginResponseDto login(loginCredentialDto)

View file

@ -154,6 +154,50 @@ class AuthenticationApi {
return null;
}
/// Get user login details and a bearer token from an API key
///
/// Note: This method returns the HTTP [Response].
Future<Response> keyLoginWithHttpInfo() async {
// ignore: prefer_const_declarations
final path = r'/auth/keyLogin';
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>[];
return apiClient.invokeAPI(
path,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Get user login details and a bearer token from an API key
Future<LoginResponseDto?> keyLogin() async {
final response = await keyLoginWithHttpInfo();
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'LoginResponseDto',) as LoginResponseDto;
}
return null;
}
/// Performs an HTTP 'POST /auth/login' operation and returns the [Response].
/// Parameters:
///

View file

@ -32,6 +32,13 @@ void main() {
// TODO
});
// Get user login details and a bearer token from an API key
//
//Future<LoginResponseDto> keyLogin() async
test('test keyLogin', () async {
// TODO
});
//Future<LoginResponseDto> login(LoginCredentialDto loginCredentialDto) async
test('test login', () async {
// TODO

View file

@ -2074,6 +2074,39 @@
]
}
},
"/auth/keyLogin": {
"get": {
"operationId": "keyLogin",
"description": "Get user login details and a bearer token from an API key",
"parameters": [],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LoginResponseDto"
}
}
}
}
},
"tags": [
"Authentication"
],
"security": [
{
"bearer": []
},
{
"cookie": []
},
{
"api_key": []
}
]
}
},
"/auth/login": {
"post": {
"operationId": "login",

View file

@ -82,6 +82,20 @@ export class AuthService {
return this.authCore.createLoginResponse(user, AuthType.PASSWORD, loginDetails);
}
public async keyLogin(
authUser: AuthUserDto,
loginDetails: LoginDetails,
): Promise<{ response: LoginResponseDto; cookie: string[] }> {
const user = await this.userCore.get(authUser.id, false);
if (!user) {
this.logger.warn(`Failed key login attempt for user ${authUser.email} from ip address ${loginDetails.clientIp}`);
throw new BadRequestException('Incorrect email or password');
}
return this.authCore.createLoginResponse(user, AuthType.PASSWORD, loginDetails);
}
public async logout(authUser: AuthUserDto, authType: AuthType): Promise<LogoutResponseDto> {
if (authUser.accessTokenId) {
await this.userTokenCore.delete(authUser.id, authUser.accessTokenId);

View file

@ -0,0 +1,41 @@
import { UserEntity } from '@app/infra/entities';
import { ApiResponseProperty } from '@nestjs/swagger';
export class LoginResponseDto {
@ApiResponseProperty()
accessToken!: string;
@ApiResponseProperty()
userId!: string;
@ApiResponseProperty()
userEmail!: string;
@ApiResponseProperty()
firstName!: string;
@ApiResponseProperty()
lastName!: string;
@ApiResponseProperty()
profileImagePath!: string;
@ApiResponseProperty()
isAdmin!: boolean;
@ApiResponseProperty()
shouldChangePassword!: boolean;
}
export function mapLoginResponse(entity: UserEntity, accessToken: string): LoginResponseDto {
return {
accessToken: accessToken,
userId: entity.id,
userEmail: entity.email,
firstName: entity.firstName,
lastName: entity.lastName,
isAdmin: entity.isAdmin,
profileImagePath: entity.profileImagePath,
shouldChangePassword: entity.shouldChangePassword,
};
}

View file

@ -42,6 +42,18 @@ export class AuthController {
return response;
}
/**
* Get user login details and a bearer token from an API key
*/
@Get('keyLogin')
async keyLogin(
@AuthUser() authUser: AuthUserDto,
@GetLoginDetails() loginDetails: LoginDetails,
): Promise<LoginResponseDto> {
const { response } = await this.service.keyLogin(authUser, loginDetails);
return response;
}
@PublicRoute()
@Post('admin-sign-up')
@ApiBadRequestResponse({ description: 'The server already has an admin' })

View file

@ -7094,6 +7094,44 @@ export const AuthenticationApiAxiosParamCreator = function (configuration?: Conf
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
* Get user login details and a bearer token from an API key
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
keyLogin: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/auth/keyLogin`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication cookie required
// authentication api_key required
await setApiKeyToObject(localVarHeaderParameter, "x-api-key", configuration)
// authentication bearer required
// http bearer authentication required
await setBearerAuthToObject(localVarHeaderParameter, configuration)
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
@ -7333,6 +7371,15 @@ export const AuthenticationApiFp = function(configuration?: Configuration) {
const localVarAxiosArgs = await localVarAxiosParamCreator.getAuthDevices(options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
* Get user login details and a bearer token from an API key
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async keyLogin(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<LoginResponseDto>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.keyLogin(options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
*
* @param {LoginCredentialDto} loginCredentialDto
@ -7416,6 +7463,14 @@ export const AuthenticationApiFactory = function (configuration?: Configuration,
getAuthDevices(options?: any): AxiosPromise<Array<AuthDeviceResponseDto>> {
return localVarFp.getAuthDevices(options).then((request) => request(axios, basePath));
},
/**
* Get user login details and a bearer token from an API key
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
keyLogin(options?: any): AxiosPromise<LoginResponseDto> {
return localVarFp.keyLogin(options).then((request) => request(axios, basePath));
},
/**
*
* @param {LoginCredentialDto} loginCredentialDto
@ -7556,6 +7611,16 @@ export class AuthenticationApi extends BaseAPI {
return AuthenticationApiFp(this.configuration).getAuthDevices(options).then((request) => request(this.axios, this.basePath));
}
/**
* Get user login details and a bearer token from an API key
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof AuthenticationApi
*/
public keyLogin(options?: AxiosRequestConfig) {
return AuthenticationApiFp(this.configuration).keyLogin(options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @param {AuthenticationApiLoginRequest} requestParameters Request parameters.