Showing
3 changed files
with
154 additions
and
9 deletions
NETWORK_TESTING_AUTHORIZATION.md
0 → 100644
| 1 | +# Network Testing - Authorization Fix | ||
| 2 | + | ||
| 3 | +## Issue Summary | ||
| 4 | +The `getCosmoteUser` endpoint was failing with a **405 Method Not Allowed** error during testing. | ||
| 5 | + | ||
| 6 | +## Root Cause Analysis | ||
| 7 | +After examining the original Objective-C implementation in `/Users/manos/Desktop/warply_projects/warply_sdk/warply_sdk_framework/SwiftWarplyFramework/SwiftWarplyFramework/Warply/Warply.m`, I found that: | ||
| 8 | + | ||
| 9 | +### Original Implementation (Objective-C) - CORRECT ✅ | ||
| 10 | +```objc | ||
| 11 | +- (void)getCosmoteUserWithSuccessBlock:(NSString*)guid :(void(^)(NSDictionary *response))success failureBlock:(void(^)(NSError *error))failure | ||
| 12 | +{ | ||
| 13 | + NSMutableDictionary* postDictionary = [[NSMutableDictionary alloc] init]; | ||
| 14 | + [postDictionary setValue:guid forKey:@"user_identifier"]; | ||
| 15 | + | ||
| 16 | + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:postDictionary options:0 error:NULL]; | ||
| 17 | + [self sendContextGetCosmoteUser:jsonData successBlock:^(NSDictionary *contextResponse) { | ||
| 18 | + // ... success handling | ||
| 19 | + } failureBlock:^(NSError *error) { | ||
| 20 | + // ... error handling | ||
| 21 | + }]; | ||
| 22 | +} | ||
| 23 | +``` | ||
| 24 | + | ||
| 25 | +And in the request implementation: | ||
| 26 | +```objc | ||
| 27 | +- (void)getCosmoteUserRequestWithType:(WLContextRequestType)requestType | ||
| 28 | +{ | ||
| 29 | + NSMutableString *urlString = [NSMutableString stringWithFormat:@"%@/partners/oauth/%@/token", _baseURL, _appUUID]; | ||
| 30 | + // ... | ||
| 31 | + [_httpClient.requestSerializer setValue:[@"Basic " stringByAppendingString:@"MVBQNFhCQzhFYTJBaUdCNkJWZGFGUERlTTNLQ3kzMjU6YzViMzAyZDY5N2FiNGY3NzhiNThhMTg0YzBkZWRmNGU="] forHTTPHeaderField:@"Authorization"]; | ||
| 32 | + // ... | ||
| 33 | + if (requestType == WLContextRequestTypePost) { | ||
| 34 | + [_httpClient POST:urlString parameters:parameters progress:nil success:successResponse failure:faliureResponse]; | ||
| 35 | + } | ||
| 36 | +} | ||
| 37 | +``` | ||
| 38 | + | ||
| 39 | +**Key Points:** | ||
| 40 | +- Uses **POST** method with JSON body | ||
| 41 | +- Sends `user_identifier` in request body, not as query parameter | ||
| 42 | +- Uses Basic Authentication with hardcoded credentials | ||
| 43 | + | ||
| 44 | +### Swift Implementation (WRONG) - BEFORE FIX ❌ | ||
| 45 | +```swift | ||
| 46 | +case .getCosmoteUser: | ||
| 47 | + return .GET // ❌ This was wrong! | ||
| 48 | +``` | ||
| 49 | + | ||
| 50 | +The Swift framework was using **GET** method, but the server expects **POST**. | ||
| 51 | + | ||
| 52 | +## Fix Applied ✅ | ||
| 53 | + | ||
| 54 | +### 1. Fixed HTTP Method in Endpoints.swift | ||
| 55 | +**File:** `SwiftWarplyFramework/SwiftWarplyFramework/Network/Endpoints.swift` | ||
| 56 | + | ||
| 57 | +**Before:** | ||
| 58 | +```swift | ||
| 59 | +case .getSingleCampaign, .getCosmoteUser, .getNetworkStatus: | ||
| 60 | + return .GET | ||
| 61 | +``` | ||
| 62 | + | ||
| 63 | +**After:** | ||
| 64 | +```swift | ||
| 65 | +case .register, .changePassword, .resetPassword, .requestOtp, .verifyTicket, .refreshToken, .logout, .getCampaigns, .getCampaignsPersonalized, | ||
| 66 | + .getCoupons, .getCouponSets, .getAvailableCoupons, | ||
| 67 | + .getMarketPassDetails, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon, .getMerchants, .sendEvent, .sendDeviceInfo, .getCosmoteUser: | ||
| 68 | + return .POST | ||
| 69 | +case .getSingleCampaign, .getNetworkStatus: | ||
| 70 | + return .GET | ||
| 71 | +``` | ||
| 72 | + | ||
| 73 | +### 2. Verified NetworkService Configuration | ||
| 74 | +The NetworkService was already correctly configured: | ||
| 75 | + | ||
| 76 | +**Basic Authentication:** ✅ Already implemented | ||
| 77 | +```swift | ||
| 78 | +private func addBasicAuthHeaders(to request: inout URLRequest, endpoint: Endpoint) { | ||
| 79 | + if endpoint.path.contains("/partners/cosmote/") || endpoint.path.contains("/partners/oauth/") { | ||
| 80 | + let basicAuth = "MVBQNFhCQzhFYTJBaUdCNkJWZGFGUERlTTNLQ3kzMjU6YzViMzAyZDY5N2FiNGY3NzhiNThhMTg0YzBkZWRmNGU=" | ||
| 81 | + request.setValue("Basic \(basicAuth)", forHTTPHeaderField: "Authorization") | ||
| 82 | + print("🔐 [NetworkService] Added Basic authentication for Cosmote endpoint") | ||
| 83 | + } | ||
| 84 | +} | ||
| 85 | +``` | ||
| 86 | + | ||
| 87 | +**Request Body:** ✅ Already implemented | ||
| 88 | +```swift | ||
| 89 | +case .getCosmoteUser(let guid): | ||
| 90 | + return [ | ||
| 91 | + "user_identifier": guid | ||
| 92 | + ] | ||
| 93 | +``` | ||
| 94 | + | ||
| 95 | +**Authentication Type:** ✅ Already implemented | ||
| 96 | +```swift | ||
| 97 | +case .getCosmoteUser: | ||
| 98 | + return .basicAuth | ||
| 99 | +``` | ||
| 100 | + | ||
| 101 | +## Expected Result | ||
| 102 | +After this fix, the `getCosmoteUser` endpoint should: | ||
| 103 | + | ||
| 104 | +1. ✅ Use **POST** method instead of GET | ||
| 105 | +2. ✅ Send `user_identifier` in JSON request body | ||
| 106 | +3. ✅ Include Basic Authentication header | ||
| 107 | +4. ✅ Receive successful response from server | ||
| 108 | + | ||
| 109 | +## Test Logs Analysis | ||
| 110 | + | ||
| 111 | +### Before Fix (ERROR): | ||
| 112 | +``` | ||
| 113 | +📤 [NetworkService] REQUEST | ||
| 114 | +🔗 URL: https://engage-stage.warp.ly/partners/oauth/f83dfde1145e4c2da69793abb2f579af/token?user_identifier=7000000833 | ||
| 115 | +🔧 Method: GET ← WRONG METHOD | ||
| 116 | +📦 Body: (No body) ← MISSING BODY | ||
| 117 | + | ||
| 118 | +📥 [NetworkService] RESPONSE | ||
| 119 | +❌ Status: 405 | ||
| 120 | +allow: OPTIONS, POST ← SERVER EXPECTS POST | ||
| 121 | +``` | ||
| 122 | + | ||
| 123 | +### After Fix (EXPECTED): | ||
| 124 | +``` | ||
| 125 | +📤 [NetworkService] REQUEST | ||
| 126 | +🔗 URL: https://engage-stage.warp.ly/partners/oauth/f83dfde1145e4c2da69793abb2f579af/token | ||
| 127 | +🔧 Method: POST ← CORRECT METHOD | ||
| 128 | +📋 Headers: | ||
| 129 | + Authorization: Basi***NGU= ← BASIC AUTH PRESENT | ||
| 130 | +📦 Body Content: {"user_identifier":"7000000833"} ← CORRECT BODY | ||
| 131 | + | ||
| 132 | +📥 [NetworkService] RESPONSE | ||
| 133 | +✅ Status: 200 ← SUCCESS EXPECTED | ||
| 134 | +``` | ||
| 135 | + | ||
| 136 | +## Next Steps | ||
| 137 | +1. Test the `getCosmoteUser` endpoint again | ||
| 138 | +2. Verify that it now returns a successful response | ||
| 139 | +3. Continue with the authorization testing checklist | ||
| 140 | + | ||
| 141 | +## Files Modified | ||
| 142 | +- `SwiftWarplyFramework/SwiftWarplyFramework/Network/Endpoints.swift` - Fixed HTTP method from GET to POST | ||
| 143 | + | ||
| 144 | +## Files Verified (No Changes Needed) | ||
| 145 | +- `SwiftWarplyFramework/SwiftWarplyFramework/Network/NetworkService.swift` - Basic auth implementation was already correct |
| ... | @@ -1913,13 +1913,13 @@ public final class WarplySDK { | ... | @@ -1913,13 +1913,13 @@ public final class WarplySDK { |
| 1913 | /// Get coupons | 1913 | /// Get coupons |
| 1914 | public func getCoupons(language: String, completion: @escaping ([CouponItemModel]?) -> Void, failureCallback: @escaping (Int) -> Void) { | 1914 | public func getCoupons(language: String, completion: @escaping ([CouponItemModel]?) -> Void, failureCallback: @escaping (Int) -> Void) { |
| 1915 | // First get merchants | 1915 | // First get merchants |
| 1916 | - getMultilingualMerchants(categories: [], defaultShown: false, center: 0.0, tags: [], uuid: "", distance: 0, parentUuids: []) { merchantsData in | 1916 | + // getMultilingualMerchants(categories: [], defaultShown: false, center: 0.0, tags: [], uuid: "", distance: 0, parentUuids: []) { merchantsData in |
| 1917 | - if let merchantsData = merchantsData { | 1917 | + // if let merchantsData = merchantsData { |
| 1918 | - DispatchQueue.main.async { | 1918 | + // DispatchQueue.main.async { |
| 1919 | - self.setMerchantList(merchantsData) | 1919 | + // self.setMerchantList(merchantsData) |
| 1920 | - } | 1920 | + // } |
| 1921 | - } | 1921 | + // } |
| 1922 | - } | 1922 | + // } |
| 1923 | 1923 | ||
| 1924 | // Get universal coupons | 1924 | // Get universal coupons |
| 1925 | getCouponsUniversal(language: language, { couponsData in | 1925 | getCouponsUniversal(language: language, { couponsData in | ... | ... |
| ... | @@ -156,9 +156,9 @@ public enum Endpoint { | ... | @@ -156,9 +156,9 @@ public enum Endpoint { |
| 156 | switch self { | 156 | switch self { |
| 157 | case .register, .changePassword, .resetPassword, .requestOtp, .verifyTicket, .refreshToken, .logout, .getCampaigns, .getCampaignsPersonalized, | 157 | case .register, .changePassword, .resetPassword, .requestOtp, .verifyTicket, .refreshToken, .logout, .getCampaigns, .getCampaignsPersonalized, |
| 158 | .getCoupons, .getCouponSets, .getAvailableCoupons, | 158 | .getCoupons, .getCouponSets, .getAvailableCoupons, |
| 159 | - .getMarketPassDetails, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon, .getMerchants, .sendEvent, .sendDeviceInfo: | 159 | + .getMarketPassDetails, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon, .getMerchants, .sendEvent, .sendDeviceInfo, .getCosmoteUser: |
| 160 | return .POST | 160 | return .POST |
| 161 | - case .getSingleCampaign, .getCosmoteUser, .getNetworkStatus: | 161 | + case .getSingleCampaign, .getNetworkStatus: |
| 162 | return .GET | 162 | return .GET |
| 163 | } | 163 | } |
| 164 | } | 164 | } | ... | ... |
-
Please register or login to post a comment