Skip to main content
GET
https://accounts.mubarokah.com
/
api
/
user
/
details
Get Detailed User Information
curl --request GET \
  --url https://accounts.mubarokah.com/api/user/details
{
  "bio": "<string>",
  "phone_number": "<string>",
  "place_of_birth": "<string>",
  "date_of_birth": "<string>",
  "address": "<string>"
}

Get Detailed User Information

This endpoint retrieves more sensitive and detailed profile information for the user associated with the provided access token. Access to this endpoint is restricted and requires specific permissions beyond basic user authentication.

Authorization Headers

Authorization
string
required
The Bearer token for authentication. Example: Bearer {YOUR_ACCESS_TOKEN}
Accept
string
default:"application/json"
Specifies the desired response format.

Required Scope & Special Approval

  • Scope: detail-user
  • Admin Approval: Access to the detail-user scope (and thus this endpoint) requires explicit administrative approval for your client application. Requesting the detail-user scope during the OAuth flow is not sufficient on its own.
Administrative Approval Required: Attempting to access this endpoint with an access token that includes the detail-user scope will still result in a 403 Forbidden error if your application has not been granted administrative approval for this level of data access. Please refer to the Scopes and Permissions documentation for details on the approval process.

Request Examples

JavaScript/Node.js

const getUserDetails = async (accessToken) => {
  try {
    const response = await fetch('https://accounts.mubarokah.com/api/user/details', {
      method: 'GET',
      headers: {
        'Authorization': `Bearer ${accessToken}`,
        'Accept': 'application/json'
      }
    });
    
    if (!response.ok) {
      const error = await response.json();
      
      if (response.status === 403) {
        if (error.error === 'unapproved_scope') {
          throw new Error('Your application needs admin approval to access detailed user information. Please contact support.');
        }
        if (error.error === 'insufficient_scope') {
          throw new Error('Access token does not have the required detail-user scope.');
        }
      }
      
      throw new Error(`HTTP ${response.status}: ${error.message || response.statusText}`);
    }
    
    return await response.json();
  } catch (error) {
    console.error('Failed to fetch user details:', error);
    throw error;
  }
};

// Safe implementation with fallback
const getCompleteUserProfile = async (accessToken) => {
  try {
    // Always get basic info first
    const basicInfo = await fetch('https://accounts.mubarokah.com/api/user', {
      headers: {
        'Authorization': `Bearer ${accessToken}`,
        'Accept': 'application/json'
      }
    }).then(res => res.json());
    
    let detailedInfo = null;
    
    try {
      // Attempt to get detailed info
      detailedInfo = await getUserDetails(accessToken);
    } catch (detailError) {
      console.warn('Detailed info not available:', detailError.message);
    }
    
    return {
      ...basicInfo,
      ...detailedInfo,
      hasDetailedAccess: detailedInfo !== null
    };
  } catch (error) {
    console.error('Failed to get user profile:', error);
    throw error;
  }
};

// Usage example
const accessToken = 'your_approved_access_token_here';
getCompleteUserProfile(accessToken)
  .then(user => {
    console.log('Complete user profile:', user);
    if (user.hasDetailedAccess) {
      console.log(`Phone: ${user.phone_number}`);
      console.log(`Address: ${user.address}`);
    } else {
      console.log('Basic profile only - detailed access not available');
    }
  })
  .catch(error => {
    console.error('Error:', error.message);
  });

Python

import requests
import json

def get_user_details(access_token):
    """Fetch detailed user information from Mubarokah ID API."""
    url = 'https://accounts.mubarokah.com/api/user/details'
    headers = {
        'Authorization': f'Bearer {access_token}',
        'Accept': 'application/json'
    }
    
    try:
        response = requests.get(url, headers=headers)
        
        if response.status_code == 403:
            error_data = response.json()
            if error_data.get('error') == 'unapproved_scope':
                raise Exception("Your application needs admin approval to access detailed user information")
            elif error_data.get('error') == 'insufficient_scope':
                raise Exception("Access token does not have the required detail-user scope")
        
        response.raise_for_status()
        return response.json()
        
    except requests.exceptions.HTTPError as e:
        if response.status_code == 401:
            raise Exception("Token expired or invalid")
        else:
            raise Exception(f"HTTP {response.status_code}: {response.text}")
    except requests.exceptions.RequestException as e:
        raise Exception(f"Request failed: {str(e)}")

def get_complete_user_profile(access_token):
    """Get complete user profile with fallback to basic info."""
    # Get basic info first
    basic_url = 'https://accounts.mubarokah.com/api/user'
    headers = {
        'Authorization': f'Bearer {access_token}',
        'Accept': 'application/json'
    }
    
    basic_response = requests.get(basic_url, headers=headers)
    basic_response.raise_for_status()
    user_profile = basic_response.json()
    
    # Try to get detailed info
    try:
        detailed_info = get_user_details(access_token)
        user_profile.update(detailed_info)
        user_profile['has_detailed_access'] = True
    except Exception as e:
        print(f"Detailed info not available: {e}")
        user_profile['has_detailed_access'] = False
    
    return user_profile

# Usage example
access_token = "your_approved_access_token_here"
try:
    user_profile = get_complete_user_profile(access_token)
    print(f"User: {user_profile['name']}")
    
    if user_profile['has_detailed_access']:
        print(f"Phone: {user_profile.get('phone_number', 'N/A')}")
        print(f"Address: {user_profile.get('address', 'N/A')}")
    else:
        print("Basic profile only - detailed access not available")
        
except Exception as error:
    print(f"Error: {error}")

PHP

<?php

function getUserDetails($accessToken) {
    $url = 'https://accounts.mubarokah.com/api/user/details';
    
    $options = [
        'http' => [
            'header' => [
                "Authorization: Bearer $accessToken",
                "Accept: application/json"
            ],
            'method' => 'GET'
        ]
    ];
    
    $context = stream_context_create($options);
    $result = file_get_contents($url, false, $context);
    
    if ($result === FALSE) {
        throw new Exception('Failed to fetch detailed user information');
    }
    
    $httpCode = intval(substr($http_response_header[0], 9, 3));
    
    if ($httpCode === 401) {
        throw new Exception('Token expired or invalid');
    } elseif ($httpCode === 403) {
        $errorData = json_decode($result, true);
        if (isset($errorData['error'])) {
            if ($errorData['error'] === 'unapproved_scope') {
                throw new Exception('Your application needs admin approval to access detailed user information');
            } elseif ($errorData['error'] === 'insufficient_scope') {
                throw new Exception('Access token does not have the required detail-user scope');
            }
        }
        throw new Exception('Access forbidden');
    } elseif ($httpCode !== 200) {
        throw new Exception("HTTP $httpCode: Request failed");
    }
    
    return json_decode($result, true);
}

function getCompleteUserProfile($accessToken) {
    // Get basic info first
    $basicUrl = 'https://accounts.mubarokah.com/api/user';
    $options = [
        'http' => [
            'header' => [
                "Authorization: Bearer $accessToken",
                "Accept: application/json"
            ],
            'method' => 'GET'
        ]
    ];
    
    $context = stream_context_create($options);
    $basicResult = file_get_contents($basicUrl, false, $context);
    
    if ($basicResult === FALSE) {
        throw new Exception('Failed to fetch basic user information');
    }
    
    $userProfile = json_decode($basicResult, true);
    
    // Try to get detailed info
    try {
        $detailedInfo = getUserDetails($accessToken);
        $userProfile = array_merge($userProfile, $detailedInfo);
        $userProfile['has_detailed_access'] = true;
    } catch (Exception $e) {
        echo "Detailed info not available: " . $e->getMessage() . "\n";
        $userProfile['has_detailed_access'] = false;
    }
    
    return $userProfile;
}

// Usage example
$accessToken = 'your_approved_access_token_here';
try {
    $userProfile = getCompleteUserProfile($accessToken);
    echo "User: {$userProfile['name']}\n";
    
    if ($userProfile['has_detailed_access']) {
        $phone = $userProfile['phone_number'] ?? 'N/A';
        $address = $userProfile['address'] ?? 'N/A';
        echo "Phone: $phone\n";
        echo "Address: $address\n";
    } else {
        echo "Basic profile only - detailed access not available\n";
    }
} catch (Exception $e) {
    echo "Error: " . $e->getMessage() . "\n";
}
?>

cURL

# Basic request
curl -X GET "https://accounts.mubarokah.com/api/user/details" \
  -H "Authorization: Bearer YOUR_APPROVED_ACCESS_TOKEN" \
  -H "Accept: application/json"

# With comprehensive error handling
curl -X GET "https://accounts.mubarokah.com/api/user/details" \
  -H "Authorization: Bearer YOUR_APPROVED_ACCESS_TOKEN" \
  -H "Accept: application/json" \
  -w "HTTP Status: %{http_code}\n" \
  -s | jq '.'

# Test script to check both basic and detailed endpoints
#!/bin/bash
TOKEN="your_access_token_here"

echo "Testing basic user info..."
curl -s -X GET "https://accounts.mubarokah.com/api/user" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json" | jq '.'

echo -e "\nTesting detailed user info..."
curl -s -X GET "https://accounts.mubarokah.com/api/user/details" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json" | jq '.'

Successful Response (200 OK)

A successful request returns a JSON object containing the user’s detailed profile information. This includes all fields from the Basic User Information endpoint, plus the additional sensitive fields listed below. Additional Response Fields:
bio
string
A short biography or description from the user. May be null.
phone_number
string
The user’s verified phone number. May be null.
place_of_birth
string
The user’s place of birth. May be null.
date_of_birth
string
The user’s date of birth in YYYY-MM-DD format. May be null.
address
string
The user’s physical address. May be null.
The availability of these fields depends on what information the user has provided to Mubarokah ID and the specific permissions granted. Some fields might be null.

Example Successful Response

{
  "id": 12345,
  "name": "Ahmad Mubarak",
  "email": "[email protected]",
  "profile_picture": "https://accounts.mubarokah.com/storage/avatars/12345.jpg",
  "username": "ahmadmubarak",
  "gender": "male",
  "bio": "Software engineer passionate about OAuth 2.0 and building great APIs for the Indonesian tech ecosystem.",
  "phone_number": "+6281234567890",
  "place_of_birth": "Jakarta, Indonesia",
  "date_of_birth": "1990-01-15",
  "address": "Jl. Sudirman No. 123, Jakarta Pusat, DKI Jakarta, 10110"
}

Error Responses

Common Error Responses

Cause: Access token is missing, invalid, or expired.
{
  "message": "Unauthenticated."
}
Or for expired tokens:
{
    "error": "token_expired",
    "error_description": "The access token provided has expired.",
    "message": "The access token provided has expired."
}
Resolution: Refresh the access token or re-authenticate the user.

Rate Limiting

This endpoint has stricter rate limiting due to the sensitive nature of the data:
  • Limit: 50 requests per minute per access token (lower than basic endpoints)
  • Reset: Rate limit resets every minute
  • Headers: Check X-RateLimit-Remaining and X-RateLimit-Reset response headers

Testing and Development

Development Checklist

Before testing this endpoint, ensure:
1

Basic Integration Working

Your application can successfully authenticate users and access the basic /api/user endpoint
2

Scope Request

Your OAuth authorization URL includes detail-user in the scope parameter:
const authURL = `https://accounts.mubarokah.com/oauth/authorize?` +
  `response_type=code&` +
  `client_id=${CLIENT_ID}&` +
  `scope=view-user detail-user&` +
  `redirect_uri=${REDIRECT_URI}&` +
  `state=${STATE}`;
3

Admin Approval

Your application has been approved for the detail-user scope through the administrative process
4

Error Handling

Your application gracefully handles unapproved_scope errors and provides appropriate user feedback

Integration Testing Script

// Comprehensive test suite for detailed user endpoint
const testDetailedUserEndpoint = async () => {
  const testScenarios = [
    {
      name: 'Approved client with valid token',
      token: 'valid_approved_token',
      expectSuccess: true
    },
    {
      name: 'Valid token but client not approved',
      token: 'valid_unapproved_token', 
      expectError: 'unapproved_scope'
    },
    {
      name: 'Token without detail-user scope',
      token: 'basic_scope_only_token',
      expectError: 'insufficient_scope'
    },
    {
      name: 'Expired token',
      token: 'expired_token',
      expectError: 'token_expired'
    }
  ];
  
  for (const scenario of testScenarios) {
    console.log(`\n🧪 Testing: ${scenario.name}`);
    
    try {
      const result = await getUserDetails(scenario.token);
      
      if (scenario.expectSuccess) {
        console.log('✅ Success - Detailed user data retrieved');
        console.log(`   User: ${result.name}`);
        console.log(`   Phone: ${result.phone_number || 'N/A'}`);
        console.log(`   Address: ${result.address || 'N/A'}`);
      } else {
        console.log('❌ Unexpected success - should have failed');
      }
    } catch (error) {
      if (scenario.expectError) {
        console.log(`✅ Expected error: ${error.message}`);
      } else {
        console.log(`❌ Unexpected error: ${error.message}`);
      }
    }
  }
};

// Performance test
const testEndpointPerformance = async (approvedToken) => {
  console.log('\n⚡ Performance testing...');
  const startTime = Date.now();
  
  try {
    const result = await getUserDetails(approvedToken);
    const endTime = Date.now();
    const duration = endTime - startTime;
    
    console.log(`✅ Response time: ${duration}ms`);
    if (duration > 2000) {
      console.warn('⚠️  Response time over 2 seconds - consider caching');
    }
  } catch (error) {
    console.log(`❌ Performance test failed: ${error.message}`);
  }
};

// Rate limit test
const testRateLimit = async (approvedToken) => {
  console.log('\n🚦 Rate limit testing...');
  const requests = [];
  
  // Send 10 rapid requests
  for (let i = 0; i < 10; i++) {
    requests.push(
      getUserDetails(approvedToken)
        .then(() => ({ success: true, request: i + 1 }))
        .catch(error => ({ success: false, error: error.message, request: i + 1 }))
    );
  }
  
  const results = await Promise.all(requests);
  const successful = results.filter(r => r.success).length;
  const rateLimited = results.filter(r => r.error?.includes('rate_limit')).length;
  
  console.log(`✅ Successful requests: ${successful}/10`);
  console.log(`🚦 Rate limited requests: ${rateLimited}/10`);
};

// Run all tests
const runComprehensiveTests = async () => {
  await testDetailedUserEndpoint();
  
  // Only run performance and rate limit tests with valid approved token
  const approvedToken = process.env.APPROVED_ACCESS_TOKEN;
  if (approvedToken) {
    await testEndpointPerformance(approvedToken);
    await testRateLimit(approvedToken);
  } else {
    console.log('\n⚠️  Set APPROVED_ACCESS_TOKEN environment variable for performance tests');
  }
};

// Execute tests
runComprehensiveTests().catch(console.error);

Production Monitoring

// Production monitoring helper
class DetailedUserAPIMonitor {
  constructor(apiClient) {
    this.apiClient = apiClient;
    this.metrics = {
      totalRequests: 0,
      successfulRequests: 0,
      approvalErrors: 0,
      scopeErrors: 0,
      averageResponseTime: 0
    };
  }
  
  async getUserDetailsWithMonitoring(accessToken) {
    const startTime = Date.now();
    this.metrics.totalRequests++;
    
    try {
      const result = await this.apiClient.getUserDetails(accessToken);
      this.metrics.successfulRequests++;
      
      const responseTime = Date.now() - startTime;
      this.updateAverageResponseTime(responseTime);
      
      return result;
    } catch (error) {
      this.trackError(error);
      throw error;
    }
  }
  
  trackError(error) {
    if (error.message.includes('unapproved_scope')) {
      this.metrics.approvalErrors++;
    } else if (error.message.includes('insufficient_scope')) {
      this.metrics.scopeErrors++;
    }
  }
  
  updateAverageResponseTime(responseTime) {
    const currentAvg = this.metrics.averageResponseTime;
    const totalSuccessful = this.metrics.successfulRequests;
    
    this.metrics.averageResponseTime = 
      (currentAvg * (totalSuccessful - 1) + responseTime) / totalSuccessful;
  }
  
  getHealthMetrics() {
    const successRate = this.metrics.totalRequests > 0 
      ? (this.metrics.successfulRequests / this.metrics.totalRequests) * 100 
      : 0;
      
    return {
      ...this.metrics,
      successRate: `${successRate.toFixed(2)}%`
    };
  }
}
Refer to the general Error Codes section for more details on other possible errors.