Skip to main content

Fetch a User

Overview

Retrieve detailed information about a specific User (API credential) by its ID. View status, role, tags, and parent Application.

Resource Access

  • User Permissions: Admin users only
  • Endpoint: GET /users/\{user_id}

Arguments

ParameterTypeRequiredDescription
user_idstringYesUnique User ID (in URL path)

Example Request

curl -X GET \
'https://api.ahrvo.network/payments/na/users/USuser456' \
-u username:password

Example Response (Enabled User)

{
"id": "USuser456",
"created_at": "2023-12-10T20:00:00Z",
"updated_at": "2023-12-10T20:00:00Z",
"enabled": true,
"role": "ROLE_MERCHANT",
"tags": {
"environment": "production",
"purpose": "web_checkout",
"created_by": "admin@example.com",
"server": "web-01"
},
"_links": {
"self": {
"href": "https://api.ahrvo.network/payments/na/users/USuser456"
},
"application": {
"href": "https://api.ahrvo.network/payments/na/applications/APapplication123"
}
}
}

Example Response (Disabled User)

{
"id": "USuser457",
"created_at": "2023-12-09T15:30:00Z",
"updated_at": "2023-12-10T20:00:00Z",
"enabled": false,
"role": "ROLE_MERCHANT",
"tags": {
"environment": "production",
"purpose": "web_checkout",
"rotation_date": "2023-12-10",
"replaced_by": "USuser456",
"disabled_reason": "key_rotation",
"disabled_by": "devops@example.com"
},
"_links": {
"self": {
"href": "https://api.ahrvo.network/payments/na/users/USuser457"
},
"application": {
"href": "https://api.ahrvo.network/payments/na/applications/APapplication123"
}
}
}

Additional Information

  • User ID: API username
    • Starts with "US"
    • Used for Basic Authentication username
    • Example: USuser456
    • Immutable (cannot change)
  • No Password: Never returned
    • password field only shown on creation
    • Cannot retrieve password later
    • Security feature
    • If lost, must create new User
    • No password reset endpoint
  • Enabled: Active status
    • true: User can authenticate
      • API requests succeed
      • Credentials are valid
      • Active key
    • false: User cannot authenticate
      • API requests fail with 401
      • Credentials rejected
      • Disabled/revoked key
    • Change via PUT /users/{id}
  • Role: Permission level
    • ROLE_MERCHANT: Standard merchant access
      • Create transfers
      • Manage payment instruments
      • View own data
      • Most common role
    • ROLE_PARTNER: Platform/partner access
      • Create merchants
      • Create applications
      • Platform-level operations
      • Higher privileges
    • Inherited from Application
    • Cannot change role
  • Created At: When User was created
    • ISO 8601 timestamp
    • UTC timezone
    • Never changes
    • Use to calculate age
    • Track rotation schedule
  • Updated At: Last modification
    • Changes when enabled/disabled
    • Changes when tags updated
    • ISO 8601 timestamp
    • Use to track recent changes
  • Tags: Custom metadata
    • Key-value pairs
    • Track purpose, environment, owner
    • Searchable (manually)
    • Mutable via PUT
    • Empty object if no tags
  • Application Link: Parent application
    • _links.application shows which Application
    • Users belong to one Application
    • Follow link for Application details
    • Cannot move User to different Application
  • Use Case: Verify credentials
    • Check if User is enabled
    • Verify environment tag
    • Confirm ownership
    • Debug authentication issues

Use Cases

Verify User Status

# Check if API key is active
curl -X GET \
'https://api.ahrvo.network/payments/na/users/USuser456' \
-u username:password

# Check enabled field
# true = active, false = disabled

Debug Authentication Issues

// Customer reports 401 errors
async function debugAuthIssue(userId) {
const user = await fetchUser(userId);

if (!user.enabled) {
console.error('User is disabled');
console.log('Disabled on:', user.updated_at);
console.log('Reason:', user.tags.disabled_reason);
console.log('Replaced by:', user.tags.replaced_by);
return 'User disabled - credentials need rotation';
}

console.log('User is enabled and should work');
console.log('Environment:', user.tags.environment);
console.log('Purpose:', user.tags.purpose);
return 'User active - check other issues';
}

Verify Environment

// Ensure using correct environment credentials
async function verifyEnvironment(userId, expectedEnv) {
const user = await fetchUser(userId);

const actualEnv = user.tags.environment;

if (actualEnv !== expectedEnv) {
console.warn(`Warning: Using ${actualEnv} credentials, expected ${expectedEnv}`);
return false;
}

console.log(`✓ Correct environment: ${actualEnv}`);
return true;
}

// Usage
await verifyEnvironment('USuser456', 'production');

Track Key Age

// Check if key needs rotation
async function checkKeyAge(userId) {
const user = await fetchUser(userId);

const created = new Date(user.created_at);
const now = new Date();
const ageInDays = Math.floor((now - created) / (1000 * 60 * 60 * 24));

console.log(`User ${userId}:`);
console.log(` Created: ${user.created_at}`);
console.log(` Age: ${ageInDays} days`);
console.log(` Environment: ${user.tags.environment}`);

if (ageInDays > 90) {
console.warn(` ⚠ Key is ${ageInDays} days old - rotation recommended`);
return { needsRotation: true, age: ageInDays };
}

console.log(` ✓ Key age is acceptable`);
return { needsRotation: false, age: ageInDays };
}

Audit User Details

// Get full User details for audit
async function auditUser(userId) {
const user = await fetchUser(userId);

return {
id: user.id,
status: user.enabled ? 'Active' : 'Disabled',
role: user.role,
created: user.created_at,
updated: user.updated_at,
ageInDays: Math.floor(
(new Date() - new Date(user.created_at)) / (1000 * 60 * 60 * 24)
),
environment: user.tags?.environment || 'untagged',
purpose: user.tags?.purpose || 'untagged',
owner: user.tags?.created_by || 'unknown',
applicationId: user._links.application.href.split('/').pop()
};
}

Find Replacement Key

// User is disabled, find replacement
async function findReplacement(disabledUserId) {
const user = await fetchUser(disabledUserId);

if (user.enabled) {
console.log('User is still enabled');
return null;
}

const replacementId = user.tags.replaced_by;

if (!replacementId) {
console.warn('No replacement key specified in tags');
return null;
}

const replacement = await fetchUser(replacementId);

console.log('Disabled key:', disabledUserId);
console.log('Replacement key:', replacementId);
console.log('Replacement status:', replacement.enabled ? 'Active' : 'Disabled');

return replacement;
}

Best Practices

  • Check Enabled Status: Before using credentials
    • Verify enabled: true
    • Disabled users cannot authenticate
    • Update credentials if disabled
    • Check tags for replacement
  • Monitor Age: Track key rotation
    • Calculate days since creation
    • Rotate keys > 90 days
    • Set reminders for rotation
    • Automate rotation checks
  • Verify Tags: Ensure proper tagging
    • Check environment tag
    • Verify purpose tag
    • Confirm owner/creator
    • Add missing tags
  • Debug Auth: First step for 401 errors
    • Fetch User to check status
    • Verify enabled status
    • Check for rotation info
    • Look for replacement key
  • Documentation: Use for reference
    • Document which User IDs are used
    • Track what each User is for
    • Link to deployment configs
    • Update when rotated

Common Workflows

Authentication Debugging Flow

  1. User reports 401 Unauthorized errors
  2. Get User ID they're using
  3. Fetch User details
  4. Check enabled field
  5. If false: Check tags for replacement
  6. If true: Check other auth issues (wrong password, etc.)
  7. Update application with correct credentials

Key Rotation Verification

async function verifyRotation(oldUserId, newUserId) {
const oldUser = await fetchUser(oldUserId);
const newUser = await fetchUser(newUserId);

// Verify old key is disabled
if (oldUser.enabled) {
console.warn('Old key is still enabled!');
return false;
}

// Verify new key is enabled
if (!newUser.enabled) {
console.error('New key is disabled!');
return false;
}

// Verify tags link them
if (oldUser.tags.replaced_by !== newUserId) {
console.warn('Old key does not reference new key in tags');
}

console.log('✓ Rotation verified successfully');
return true;
}

Environment Validation

// Before deploying to production
async function validateProductionKey(userId) {
const user = await fetchUser(userId);

const checks = {
enabled: user.enabled,
environment: user.tags.environment === 'production',
role: user.role === 'ROLE_MERCHANT',
tagged: Object.keys(user.tags).length > 0
};

const allPassed = Object.values(checks).every(v => v);

if (!allPassed) {
console.error('Production key validation failed:');
console.log(checks);
throw new Error('Invalid production credentials');
}

console.log('✓ Production credentials validated');
return true;
}

Compliance Check

// Verify User meets compliance requirements
async function complianceCheck(userId) {
const user = await fetchUser(userId);

const issues = [];

// Check age
const ageInDays = (new Date() - new Date(user.created_at)) / (1000 * 60 * 60 * 24);
if (ageInDays > 90) {
issues.push(`Key age (${Math.floor(ageInDays)} days) exceeds 90-day rotation policy`);
}

// Check tags
if (!user.tags.environment) {
issues.push('Missing environment tag');
}
if (!user.tags.created_by) {
issues.push('Missing created_by tag (ownership unclear)');
}
if (!user.tags.purpose) {
issues.push('Missing purpose tag');
}

// Check disabled keys
if (!user.enabled) {
const disabledDate = new Date(user.updated_at);
const daysSinceDisabled = (new Date() - disabledDate) / (1000 * 60 * 60 * 24);

if (daysSinceDisabled > 30) {
issues.push(`Disabled key older than 30 days - consider deletion`);
}
}

return {
compliant: issues.length === 0,
issues
};
}

Security Considerations

  • Password Never Visible: By design
    • Cannot retrieve password after creation
    • Must create new User if lost
    • Prevents credential leakage
    • Store password securely on creation
  • Verify Before Use: Always check enabled
    • Don't assume credentials work
    • Check status before deployment
    • Verify environment tag matches
    • Confirm key is active
  • Audit Trail: Track changes
    • updated_at shows last change
    • Tags can track who disabled and why
    • Log when fetching User details
    • Monitor for suspicious access
  • Limited Access: Restrict who can view
    • Only admin/devops team
    • Shows credential status
    • Could aid attacker
    • Audit access to this endpoint
  • POST /applications/{id}/users: Create new User
  • GET /users: List all Users
  • PUT /users/{id}: Update User (disable, update tags)
  • GET /applications/{id}: View parent Application