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

feat(users): implement api route to add new user to cognito #615

Merged
merged 2 commits into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions app/web/src/app/api/clients/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Clients API

Integrate with AWS Cognito to fetch client list and add new client to user pool.

## Endpoint

### 1. Fetch client list

This api fetched all users with role CLIENT in cognito

```json
GET /api/clients
```

```json
Request: http://localhost:3000/api/clients
Response:
{
"data": [
{
"username": "thvo-maintainer",
"firstName": "Maintainer",
"lastName": "Thvo",
"email": "thvo@privacypal.awsapps.com"
},
{
"username": "testuser1",
"firstName": "Marry",
"lastName": "Lane",
"email": "privacypaltest@gmail.com"
},
...
]
}
```

### 2. Add new user to client group

This api adds new user to cognito and assigns CLIENT role to them

```json
PUT /api/clients
```

#### Request body required:

"username": new client username
"email": new client email

```json
Request: http://localhost:3000/api/clients
{
"username": "ngan-test-new-user",
"email": "jill01009@gmail.com"
}
```

```json
Response:
{
"data": {
"message": "User successfully added to user pool"
}
}
```
63 changes: 61 additions & 2 deletions app/web/src/app/api/clients/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,23 @@
* limitations under the License.
*/

import { getClients } from "@app/actions";
import { JSONResponse, RESPONSE_NOT_FOUND } from "@lib/response";
import { getClients, getLoggedInUser } from "@app/actions";
import { addUserToGroup, createUser } from "@lib/cognito";
import {
JSONErrorBuilder,
JSONResponse,
JSONResponseBuilder,
RESPONSE_NOT_AUTHORIZED,
RESPONSE_NOT_FOUND,
} from "@lib/response";
import { UserRole } from "@lib/userRole";
import { resolveNs } from "dns";
import { NextRequest } from "next/server";

interface RequestBody {
username: string;
email: string;
}

export const dynamic = "force-dynamic";

Expand All @@ -31,3 +46,47 @@ export async function GET() {

return Response.json(RESPONSE_NOT_FOUND, { status: 404 });
}

export async function PUT(req: NextRequest) {
const body: RequestBody = await req.json();

// TODO: Consider removing this code and implement the check in middleware
const loggedinUser = await getLoggedInUser();
Copy link
Contributor

Choose a reason for hiding this comment

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

Added new issue: #620


if (loggedinUser?.role !== UserRole.PROFESSIONAL) {
// only allow professional to add new user
return Response.json(RESPONSE_NOT_AUTHORIZED, { status: 401 });
}

const { username, email } = body;
if (!username || !email) {
return Response.json(
JSONResponseBuilder.from(
400,
JSONErrorBuilder.from(400, "Missing username or email"),
),
{ status: 400 },
);
}

// Create new user to user pool
try {
await createUser({ username: username, email: email });
await addUserToGroup({ username: username, groupName: UserRole.CLIENT });
} catch {
return Response.json(
JSONResponseBuilder.from(
500,
JSONErrorBuilder.from(500, "Internal server error"),
),
{ status: 500 },
);
}

return Response.json(
{
data: { message: "User successfully added to user pool" },
},
{ status: 200 },
);
}
74 changes: 74 additions & 0 deletions app/web/src/lib/cognito.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
* limitations under the License.
*/
import {
AdminAddUserToGroupCommand,
AdminCreateUserCommand,
AttributeType,
CognitoIdentityProviderClient,
ListUsersCommand,
Expand Down Expand Up @@ -133,3 +135,75 @@ function parseUsersInfo(users: UserType[]): CognitoUser[] {
});
return result;
}

interface NewUserInfo {
username: string;
email: string;
}
/**
*
* Call Cognito and create new user in user pool
* @param username string
* @param email string
* @returns AdminCreateUserResponse
* {
* User: {
* Username: "STRING_VALUE",
* Attributes: [
* {
* Name: "STRING_VALUE",
* Value: "STRING_VALUE",
* },
* ],
* UserCreateDate: new Date("TIMESTAMP"),
* UserLastModifiedDate: new Date("TIMESTAMP"),
* Enabled: true || false,
* UserStatus: "UNCONFIRMED" || "CONFIRMED" || "ARCHIVED" || "COMPROMISED" || "UNKNOWN" || "RESET_REQUIRED" || "FORCE_CHANGE_PASSWORD",
* MFAOptions: [
* {
* DeliveryMedium: "SMS" || "EMAIL",
* AttributeName: "STRING_VALUE",
* },
* ],
* },
* };
*/
export async function createUser(info: NewUserInfo) {
const input = {
UserPoolId: userPoolId,
Username: info.username,
UserAttributes: [
{
Name: "email",
Value: info.email,
},
],
};
const command = new AdminCreateUserCommand(input);
const response = await client.send(command);
return response;
}

interface GroupInfo {
username: string;
groupName: UserRole;
}

/**
* Add user to cognito group given user name
* @param username string
* @param groupName string
* @return AdminAddUserToGroupCommand Output
*
*/
export async function addUserToGroup(info: GroupInfo) {
const input = {
UserPoolId: userPoolId,
Username: info.username,
GroupName: info.groupName,
};

const command = new AdminAddUserToGroupCommand(input);
const response = client.send(command);
return response;
}
Loading