メインコンテンツまでスキップ
バージョン: 🚧 Canary

🆔 Identity Service

Testing Status

The Identity Service provides a complete REST API for managing identity entities with read/update/delete, lock/unlock, and security management. It's built using the NodeBlocks functional composition approach and integrates seamlessly with MongoDB.


🚀 Quickstart

import express from 'express';

import {middlewares, services, drivers} from '@nodeblocks/backend-sdk';

const {nodeBlocksErrorMiddleware} = middlewares;
const {identitiesService} = services;
const {withMongo} = drivers;

const connectToDatabase = withMongo('mongodb://localhost:27017/?authSource=admin', 'dev', 'user', 'password');

express()
.use(
identitiesService(await connectToDatabase('identities'), {
authSecrets: {
authEncSecret: 'your-encryption-secret',
authSignSecret: 'your-signing-secret',
},
authMode: 'bearer', // or 'cookie',
identity: {
typeIds: {
admin: '100',
guest: '000',
regular: '001',
},
},
}),
)
.use(nodeBlocksErrorMiddleware())
.listen(8089, () => console.log('Server running'));

📋 Endpoint Summary

MethodPathDescriptionAuthorization
GET/identities/:identityIdRetrieve an identity by IDAccess token required (bearer by default, cookie when authMode: 'cookie'); admin only
GET/identitiesList/filter identitiesAccess token required (bearer by default, cookie when authMode: 'cookie'); admin only
PATCH/identities/:identityIdUpdate an identityAccess token required (bearer by default, cookie when authMode: 'cookie'); admin only
POST/identities/:identityId/lockLock an identity for securityAccess token required (bearer by default, cookie when authMode: 'cookie'); admin only
POST/identities/:identityId/unlockUnlock a locked identityAccess token required (bearer by default, cookie when authMode: 'cookie'); admin only
DELETE/identities/:identityIdDelete an identityAccess token required (bearer by default, cookie when authMode: 'cookie'); admin only

🗄️ Entity Schema

The identity entity combines base fields (auto-generated) with identity-specific data:

{
"id": "string",
"createdAt": "string (datetime)",
"updatedAt": "string (datetime)",
"email": "string",
"emailVerified": "boolean",
"password": "string (hashed)",
"typeId": "string",
"attempts": "number",
"locked": "boolean",
"deactivatedAt": "string (datetime) | null",
"provider": "string",
"providerId": "string"
}

Field Details

FieldTypeAuto-GeneratedRequiredDescription
idstringUnique identifier (UUID)
createdAtdatetimeCreation timestamp
updatedAtdatetimeLast modification timestamp
emailstringUser's email address
emailVerifiedbooleanEmail verification status
passwordstringHashed password (bcrypt)
typeIdstringUser type identifier (e.g., "100" for admin)
attemptsnumberLogin attempt counter
lockedbooleanAccount lock status
deactivatedAtdatetime or nullAccount deactivation timestamp, or null when active
providerstringOAuth provider identifier
providerIdstringProvider-specific identity identifier

📝 Note: Auto-generated fields are set by the service and should not be included in create/update requests.

🔒 Security Note: For security reasons, the password field is never returned in API responses. It is stored securely in the database using bcrypt hashing but is filtered out before sending responses to clients.


🔐 Authentication Headers

For all endpoints, include the following headers:

Authorization: Bearer <access_token>
x-nb-fingerprint: <device_fingerprint>

⚠️ Important: The x-nb-fingerprint header is required for all authenticated requests if fingerprint was specified during authorization. Without it, requests will return 401 Unauthorized.

🍪 Cookie auth: When authMode: 'cookie', protected routes read the access token from cookies. Host apps must register cookie-parser.

🔒 Admin Access Required: All Identity Service endpoints require admin permissions. The access token must belong to a user with admin privileges (typeId: "100" by default). Non-admin users will receive a 403 Forbidden response.


🔧 API Endpoints

1. Get Identity by ID

Retrieves a specific identity by their unique ID.

Request:

  • Method: GET
  • Path: /identities/:identityId
  • Headers:
    • Authorization: Bearer <token>
    • x-nb-fingerprint: <device-fingerprint>
  • Authorization: Access token required (bearer by default, cookie when authMode: 'cookie'); admin only

URL Parameters:

ParameterTypeRequiredDescription
identityIdstringUnique identity identifier

Response Body:

FieldTypeDescription
idstringUnique identity identifier
emailstringUser's email address
emailVerifiedbooleanEmail verification status
typeIdstringUser type identifier
attemptsnumberLogin attempt counter
lockedbooleanAccount lock status
createdAtstringCreation timestamp
updatedAtstringLast update timestamp

Validation:

  • Schema Validation: None (GET request)
  • Route Validators:
    • Require authenticated request (access token)
    • Require admin role

Example Request:

curl {{host}}/identities/811ff0a3-a26f-447b-b68a-dd83ea4000b9 \
-H "Authorization: Bearer your-access-token-here"

Success Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
"attempts": 0,
"email": "admin@example.com",
"emailVerified": true,
"locked": false,
"createdAt": "2025-07-29T07:37:01.735Z",
"id": "811ff0a3-a26f-447b-b68a-dd83ea4000b9",
"updatedAt": "2025-07-29T07:39:36.564Z",
"typeId": "100"
}

Error Responses:

When no authorization token is provided:

HTTP/1.1 401 Unauthorized
Content-Type: application/json

{
"error": {
"message": "token could not be verified"
}
}

When no identity exists with the provided ID:

HTTP/1.1 404 Not Found
Content-Type: application/json

{
"error": {
"message": "Identity not found"
}
}

When an unexpected error occurs (database connection issues, etc.):

HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{
"error": {
"message": "Failed to get identity"
}
}

2. List Identities

Retrieves a list of identities. Query parameters are schema-validated, but the handler returns a full array and does not implement server-side pagination.

Request:

  • Method: GET
  • Path: /identities
  • Headers:
    • Authorization: Bearer <token>
    • x-nb-fingerprint: <device-fingerprint>
  • Authorization: Access token required (bearer by default, cookie when authMode: 'cookie'); admin only

Query Parameters:

ParameterTypeRequiredDescription
namestringAccepted by the schema and passed to Mongo find (identity documents have no name field by default)
pagenumberAccepted by the schema and forwarded to the Mongo filter object; not used for pagination
limitnumberAccepted by the schema and forwarded to the Mongo filter object; not used for pagination

Response Body:

FieldTypeDescription
idstringUnique identity identifier
emailstringUser's email address
emailVerifiedbooleanEmail verification status
typeIdstringUser type identifier
attemptsnumberLogin attempt counter
lockedbooleanAccount lock status
createdAtstringCreation timestamp
updatedAtstringLast update timestamp

Validation:

  • Schema Validation: Query parameter validation for name (string), page and limit (integers with min/max constraints). Note: page/limit are not used to paginate results; they are forwarded as plain query keys to the Mongo filter.
  • Route Validators:
    • Require authenticated request (access token)
    • Require admin role

Example Requests:

List all identities:

curl {{host}}/identities \
-H "Authorization: Bearer <access-token>"

Filter by name:

curl "{{host}}/identities?name=admin" \
-H "Authorization: Bearer <access-token>"

Combine filters with extra query params:

curl "{{host}}/identities?name=admin&page=1&limit=20" \
-H "Authorization: Bearer <access-token>"

Success Response:

HTTP/1.1 200 OK
Content-Type: application/json

[
{
"attempts": 0,
"email": "admin@example.com",
"emailVerified": true,
"locked": false,
"createdAt": "2025-07-29T07:37:01.735Z",
"id": "811ff0a3-a26f-447b-b68a-dd83ea4000b9",
"updatedAt": "2025-07-29T07:39:36.564Z",
"typeId": "100"
},
{
"attempts": 0,
"email": "user@example.com",
"emailVerified": false,
"locked": false,
"createdAt": "2025-07-29T07:38:15.123Z",
"id": "922ff1b4-b37g-558c-c79b-ee94fb5001c0",
"updatedAt": "2025-07-29T07:38:15.123Z",
"typeId": "001"
}
]

Error Responses:

When user is not authorized to access the resource:

HTTP/1.1 403 Forbidden
Content-Type: application/json

{
"error": {
"message": "Identity is not authorized to access this resource"
}
}

When an unexpected error occurs (database connection issues, invalid filter syntax, etc.):

HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{
"error": {
"message": "Failed to find identities"
}
}

3. Update Identity

Updates an existing identity with partial data.

Request:

  • Method: PATCH
  • Path: /identities/:identityId
  • Headers:
    • Content-Type: application/json
    • Authorization: Bearer <token>
    • x-nb-fingerprint: <device-fingerprint>
  • Authorization: Access token required (bearer by default, cookie when authMode: 'cookie'); admin only

URL Parameters:

ParameterTypeRequiredDescription
identityIdstringUnique identity identifier

Request Body (object required; at least one field must be provided):

FieldTypeRequiredDescription
emailstringUser's email address
emailVerifiedbooleanEmail verification status
typeIdstringUser type identifier

Response Body:

FieldTypeDescription
idstringUnique identity identifier
emailstringUpdated email address
emailVerifiedbooleanUpdated email verification status
typeIdstringUpdated user type identifier
attemptsnumberUpdated login attempt counter
lockedbooleanUpdated account lock status
createdAtstringCreation timestamp
updatedAtstringLast update timestamp

Validation:

  • Schema Validation: Basic validation (all fields optional by field, type checking)
  • Route Validators:
    • Require authenticated request (access token)
    • Require admin role

Note: An empty JSON object is rejected by the handler with 400 Identity data is required because the update payload must contain at least one field.

Example Request:

curl -X PATCH {{host}}/identities/811ff0a3-a26f-447b-b68a-dd83ea4000b9 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '{
"email": "admin@example.com",
"emailVerified": true,
"typeId": "200"
}'

Success Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
"attempts": 0,
"email": "admin@example.com",
"locked": false,
"createdAt": "2025-07-29T07:37:01.735Z",
"id": "811ff0a3-a26f-447b-b68a-dd83ea4000b9",
"updatedAt": "2025-07-29T07:42:07.611Z",
"typeId": "200"
}

Error Responses:

When no identity exists with the provided ID:

HTTP/1.1 404 Not Found
Content-Type: application/json

{
"error": {
"message": "Identity not found"
}
}

When the request body is empty:

HTTP/1.1 400 Bad Request
Content-Type: application/json

{
"error": {
"message": "Identity data is required"
}
}

When the update operation doesn't modify any data (no changes detected):

HTTP/1.1 400 Bad Request
Content-Type: application/json

{
"error": {
"message": "Failed to update identity"
}
}

When an unexpected error occurs (database connection issues, etc.):

HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{
"error": {
"message": "Failed to update identity"
}
}

4. Delete Identity

Permanently deletes an identity from the system.

Request:

  • Method: DELETE
  • Path: /identities/:identityId
  • Headers:
    • Authorization: Bearer <token>
    • x-nb-fingerprint: <device-fingerprint>
  • Authorization: Access token required (bearer by default, cookie when authMode: 'cookie'); admin only

URL Parameters:

ParameterTypeRequiredDescription
identityIdstringUnique identity identifier

Response Body:

FieldTypeDescription
No response body-Delete endpoint returns no response body on success

Validation:

  • Schema Validation: None (DELETE request)
  • Route Validators:
    • Require authenticated request (access token)
    • Require admin role

Example Request:

curl -X DELETE {{host}}/identities/be265523-7fea-44a1-a0a2-dc5dabdb9f0c \
-H "Authorization: Bearer <access-token>"

Success Response:

HTTP/1.1 204 No Content

Error Responses:

When user is not authorized to access the resource:

HTTP/1.1 403 Forbidden
Content-Type: application/json

{
"error": {
"message": "Identity is not authorized to access this resource"
}
}

When no identity exists with the provided ID:

HTTP/1.1 404 Not Found
Content-Type: application/json

{
"error": {
"message": "Identity not found"
}
}

When an unexpected error occurs (database connection issues, etc.):

HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{
"error": {
"message": "Failed to delete identity"
}
}

5. Lock Identity

Locks an identity account to prevent access for security reasons.

Request:

  • Method: POST
  • Path: /identities/:identityId/lock
  • Headers:
    • Authorization: Bearer <token>
    • x-nb-fingerprint: <device-fingerprint>
  • Authorization: Access token required (bearer by default, cookie when authMode: 'cookie'); admin only

URL Parameters:

ParameterTypeRequiredDescription
identityIdstringUnique identity identifier to lock

Response Body:

FieldTypeDescription
No response body-Lock endpoint returns no response body on success

Validation:

  • Schema Validation: Path parameter validation
  • Route Validators:
    • Require authenticated request (access token)
    • Require admin role

Example Request:

curl -X POST {{host}}/identities/be265523-7fea-44a1-a0a2-dc5dabdb9f0c/lock \
-H "Authorization: Bearer <access-token>" \
-H "x-nb-fingerprint: <device-fingerprint>"

Success Response:

HTTP/1.1 204 No Content

Error Responses:

When user is not authorized:

HTTP/1.1 403 Forbidden
Content-Type: application/json

{
"error": {
"message": "Identity is not authorized to access this resource"
}
}

When identity does not exist:

HTTP/1.1 404 Not Found
Content-Type: application/json

{
"error": {
"message": "Identity not found"
}
}

6. Unlock Identity

Unlocks a previously locked identity account to restore access.

Request:

  • Method: POST
  • Path: /identities/:identityId/unlock
  • Headers:
    • Authorization: Bearer <token>
    • x-nb-fingerprint: <device-fingerprint>
  • Authorization: Access token required (bearer by default, cookie when authMode: 'cookie'); admin only

URL Parameters:

ParameterTypeRequiredDescription
identityIdstringUnique identity identifier to unlock

Response Body:

FieldTypeDescription
No response body-Unlock endpoint returns no response body on success

Validation:

  • Schema Validation: Path parameter validation
  • Route Validators:
    • Require authenticated request (access token)
    • Require admin role

Example Request:

curl -X POST {{host}}/identities/be265523-7fea-44a1-a0a2-dc5dabdb9f0c/unlock \
-H "Authorization: Bearer <access-token>" \
-H "x-nb-fingerprint: <device-fingerprint>"

Success Response:

HTTP/1.1 204 No Content

Error Responses:

When user is not authorized:

HTTP/1.1 403 Forbidden
Content-Type: application/json

{
"error": {
"message": "Identity is not authorized to access this resource"
}
}

When identity does not exist:

HTTP/1.1 404 Not Found
Content-Type: application/json

{
"error": {
"message": "Identity not found"
}
}

🗄️ Datastore

CollectionRequiredDescription
identitiesIdentity documents

⚙️ Configuration Options

Service Configuration

interface IdentitiesServiceConfiguration {
authSecrets: {
authEncSecret: string; // JWT encryption secret
authSignSecret: string; // JWT signing secret
};
authMode?: 'bearer' | 'cookie'; // Default: bearer behavior when unset
identity?: {
typeIds?: {
admin: string; // Admin user type identifier
guest: string; // Guest user type identifier
regular: string; // Regular user type identifier
};
};
}

Configuration Details

The identity service configuration is organized into logical groups for security and user type management.

🔐 Security Settings

authSecrets - JWT token security secrets

  • Type: { authEncSecret: string; authSignSecret: string }
  • Description: Secret keys for JWT encryption and signing (used for token validation)
  • Required: Yes (for production)
  • Child Properties:
    • authEncSecret: Secret key for JWT payload encryption
    • authSignSecret: Secret key for JWT signature verification

👥 User Type Settings

identity.typeIds - User type identifier configuration

  • Type: { admin?: string; guest?: string; regular?: string }
  • Description: Custom user type identifiers for role-based access control
  • Default: undefined (uses default type validation)
  • Child Properties:
    • admin: Admin user type identifier
      • Type: string
      • Description: Custom identifier for admin users
      • Use Case: Role-based access control for administrative operations
      • Example: "admin", "administrator", "superuser"
    • guest: Guest user type identifier
      • Type: string
      • Description: Custom identifier for guest users
      • Use Case: Limited access for unauthenticated or temporary users
      • Example: "guest", "visitor", "anonymous"
    • regular: Regular user type identifier
      • Type: string
      • Description: Custom identifier for regular users
      • Use Case: Standard user access permissions
      • Example: "user", "member", "customer"

Example Configuration

const identityConfig = {
authSecrets: {
authEncSecret: process.env.AUTH_ENC_SECRET || 'your-enc-secret',
authSignSecret: process.env.AUTH_SIGN_SECRET || 'your-sign-secret',
},
identity: {
typeIds: {
admin: '100',
guest: '000',
regular: '001',
},
},
};

🚨 Error Handling

All identity service errors return JSON format with appropriate HTTP status codes:

Common Error Codes

StatusError MessageDescription
400Identity data is requiredUpdate request body is empty
400Failed to update identityUpdate operation doesn't modify any data (no changes detected)
401token could not be verifiedMissing or invalid authorization token
403Identity is not authorized to access this resourceInsufficient permissions for the requested operation
404Identity not foundIdentity doesn't exist for GET/PATCH/DELETE/LOCK/UNLOCK operations
500Failed to get identityDatabase connection issues or unexpected failures during retrieval
500Failed to find identitiesDatabase connection issues, invalid filter syntax, or unexpected failures during listing
500Failed to update identityDatabase connection issues or unexpected failures during update
500Failed to delete identityDatabase connection issues or unexpected failures during deletion

Error Response Format

{
"error": {
"message": "Error message description",
"data": ["Additional error details"]
}
}