Skip to content

Commit dd3d890

Browse files
authored
Merge pull request #1187 from OneSignal/user_model/jwt_token_handling
[User model] JWT token handling
2 parents 3e851d9 + e4d4512 commit dd3d890

File tree

5 files changed

+67
-25
lines changed

5 files changed

+67
-25
lines changed

iOS_SDK/OneSignalSDK/OneSignalUser/Source/OSIdentityModel.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ class OSIdentityModel: OSModel {
3939
}
4040

4141
var aliases: [String: String] = [:]
42+
43+
// TODO: We need to make this token secure
44+
public var jwtBearerToken: String?
4245

4346
// MARK: - Initialization
4447

iOS_SDK/OneSignalSDK/OneSignalUser/Source/OSUserRequests.swift

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ class OSRequestCreateUser: OneSignalRequest, OSUserRequest {
192192
let pushSubscriptionModel: OSSubscriptionModel
193193

194194
func prepareForExecution() -> Bool {
195+
self.addJWTHeader(identityModel:identityModel)
195196
// The pushSub doesn't need to have a token.
196197
return true
197198
}
@@ -267,6 +268,7 @@ class OSRequestIdentifyUser: OneSignalRequest, OSUserRequest {
267268
// requires a onesignal_id to send this request
268269
func prepareForExecution() -> Bool {
269270
if let onesignalId = identityModelToIdentify.onesignalId {
271+
self.addJWTHeader(identityModel: identityModelToIdentify)
270272
self.path = "user/by/\(OS_ONESIGNAL_ID)/\(onesignalId)/identity"
271273
return true
272274
} else {
@@ -342,6 +344,7 @@ class OSRequestFetchUser: OneSignalRequest, OSUserRequest {
342344
// If there is an alias, use that
343345
if let aliasLabelToUse = aliasLabel,
344346
let aliasIdToUse = aliasId {
347+
self.addJWTHeader(identityModel: identityModel)
345348
self.path = "user/by/\(aliasLabelToUse)/\(aliasIdToUse)"
346349
return true
347350
}
@@ -398,6 +401,7 @@ class OSRequestAddAliases: OneSignalRequest, OSUserRequest {
398401
// requires a `onesignal_id` to send this request
399402
func prepareForExecution() -> Bool {
400403
if let onesignalId = identityModel.onesignalId {
404+
self.addJWTHeader(identityModel: identityModel)
401405
self.path = "user/by/\(OS_ONESIGNAL_ID)/\(onesignalId)/identity"
402406
return true
403407
} else {
@@ -447,6 +451,7 @@ class OSRequestRemoveAlias: OneSignalRequest, OSUserRequest {
447451

448452
func prepareForExecution() -> Bool {
449453
if let onesignalId = identityModel.onesignalId {
454+
self.addJWTHeader(identityModel: identityModel)
450455
self.path = "user/by/\(OS_ONESIGNAL_ID)/\(onesignalId)/identity/\(labelToRemove)"
451456
return true
452457
} else {
@@ -496,6 +501,7 @@ class OSRequestUpdateProperties: OneSignalRequest, OSUserRequest {
496501

497502
func prepareForExecution() -> Bool {
498503
if let onesignalId = identityModel.onesignalId {
504+
self.addJWTHeader(identityModel: identityModel)
499505
self.path = "user/by/\(OS_ONESIGNAL_ID)/\(onesignalId)"
500506
return true
501507
} else {
@@ -560,6 +566,7 @@ class OSRequestCreateSubscription: OneSignalRequest, OSUserRequest {
560566
// Need the onesignal_id of the user
561567
func prepareForExecution() -> Bool {
562568
if let onesignalId = identityModel.onesignalId {
569+
self.addJWTHeader(identityModel: identityModel)
563570
self.path = "user/by/\(OS_ONESIGNAL_ID)/\(onesignalId)/subscription"
564571
return true
565572
} else {
@@ -636,8 +643,9 @@ class OSRequestTransferSubscription: OneSignalRequest, OSUserRequest {
636643
self.parameters?["identity"] = [label: id]
637644
return true
638645
}
639-
if let onesignalId = identityModel?.onesignalId {
646+
if let identityModel = identityModel, let onesignalId = identityModel.onesignalId {
640647
self.parameters?["identity"] = [OS_ONESIGNAL_ID: onesignalId]
648+
self.addJWTHeader(identityModel: identityModel)
641649
return true
642650
} else {
643651
return false
@@ -807,3 +815,14 @@ class OSRequestDeleteSubscription: OneSignalRequest, OSUserRequest {
807815
_ = prepareForExecution()
808816
}
809817
}
818+
819+
internal extension OneSignalRequest {
820+
func addJWTHeader(identityModel: OSIdentityModel) {
821+
guard let token = identityModel.jwtBearerToken else {
822+
return
823+
}
824+
var additionalHeaders = self.additionalHeaders ?? [String:String]()
825+
additionalHeaders["Authorization"] = "Bearer \(token)"
826+
self.additionalHeaders = additionalHeaders
827+
}
828+
}

iOS_SDK/OneSignalSDK/OneSignalUser/Source/OneSignalUserManagerImpl.swift

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ import OneSignalNotifications
6666
func removeSmsNumber(_ number: String) -> Bool
6767
// Language
6868
func setLanguage(_ language: String?)
69+
// JWT Token Expire
70+
typealias OSJwtCompletionBlock = (_ newJwtToken: String) -> Void
71+
typealias OSJwtExpiredHandler = (_ externalId: String, _ completion: OSJwtCompletionBlock) -> Void
72+
func onJwtExpired(expiredHandler: @escaping OSJwtExpiredHandler)
6973

7074
// TODO: UM This is a temporary function to create a push subscription for testing
7175
func testCreatePushSubscription(subscriptionId: String, token: String, enabled: Bool)
@@ -92,6 +96,8 @@ public class OneSignalUserManagerImpl: NSObject, OneSignalUserManager {
9296
}
9397

9498
private var hasCalledStart = false
99+
100+
private var jwtExpiredHandler: OSJwtExpiredHandler?
95101

96102
var user: OSUserInternal {
97103
guard !OneSignalConfigManager.shouldAwaitAppIdAndLogMissingPrivacyConsent(forMethod: nil) else {
@@ -224,7 +230,7 @@ public class OneSignalUserManagerImpl: NSObject, OneSignalUserManager {
224230
prepareForNewUser()
225231

226232
let newUser = setNewInternalUser(externalId: externalId, pushSubscriptionModel: pushSubscriptionModel)
227-
233+
newUser.identityModel.jwtBearerToken = token
228234
OSUserExecutor.createUser(newUser)
229235
return self.user
230236
}
@@ -265,11 +271,11 @@ public class OneSignalUserManagerImpl: NSObject, OneSignalUserManager {
265271
print("🔥 OneSignalUserManagerImpl private _login(\(externalId ?? "nil")) called")
266272

267273
// If have token, validate token. Account for this being a requirement.
268-
269274
// Logging into an identified user from an anonymous user
270275
if let externalId = externalId,
271276
let user = _user,
272277
user.isAnonymous {
278+
user.identityModel.jwtBearerToken = token
273279
identifyUser(externalId: externalId, currentUser: user)
274280
return self.user
275281
}
@@ -386,6 +392,19 @@ public class OneSignalUserManagerImpl: NSObject, OneSignalUserManager {
386392
identityModel: identityModel
387393
)
388394
}
395+
396+
397+
private func fireJwtExpired() {
398+
guard let externalId = user.identityModel.externalId, let jwtExpiredHandler = self.jwtExpiredHandler else {
399+
return
400+
}
401+
jwtExpiredHandler(externalId) { [self] (newToken) -> Void in
402+
guard user.identityModel.externalId == externalId else {
403+
return
404+
}
405+
user.identityModel.jwtBearerToken = newToken
406+
}
407+
}
389408
}
390409

391410
// MARK: - Sessions
@@ -425,6 +444,10 @@ extension OneSignalUserManagerImpl {
425444
}
426445

427446
extension OneSignalUserManagerImpl: OSUser {
447+
public func onJwtExpired(expiredHandler: @escaping OSJwtExpiredHandler) {
448+
jwtExpiredHandler = expiredHandler
449+
}
450+
428451
public var User: OSUser {
429452
start()
430453
return self

iOS_SDK/OneSignalSDK/UnitTests/UserModelObjcTests.m

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ of this software and associated documentation files (the "Software"), to deal
2626
*/
2727

2828
#import <XCTest/XCTest.h>
29-
#import "OneSignal.h"
29+
#import "OneSignalFramework.h"
3030

3131
@interface UserModelObjcTests : XCTestCase
3232

@@ -199,4 +199,12 @@ - (void)testTempTester {
199199
BOOL paused = [OneSignal.InAppMessages paused];
200200
}
201201

202+
- (void)testOnJwtExpired {
203+
// TODO: Fix autocompletion. It isn't auto completing parameter names which makes this unreadable
204+
[OneSignal.User onJwtExpiredWithExpiredHandler:^(NSString * _Nonnull externalId, void (^ _Nonnull completion)(NSString * _Nonnull)) {
205+
NSString *newToken = externalId;
206+
completion(newToken);
207+
}];
208+
}
209+
202210
@end

iOS_SDK/OneSignalSDK/UnitTests/UserModelSwiftTests.swift

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -26,25 +26,7 @@
2626
*/
2727

2828
import XCTest
29-
30-
// TODO: UM This goes elsewhere
31-
extension OneSignal {
32-
static var User: OSUser {
33-
return __user()
34-
}
35-
36-
static var Notifications: OSNotifications.Type {
37-
return OneSignal.__notifications()
38-
}
39-
40-
static var Session: OSSession.Type {
41-
return __session()
42-
}
43-
44-
static var InAppMessages: OSInAppMessages.Type {
45-
return __inAppMessages()
46-
}
47-
}
29+
import OneSignalFramework
4830

4931
extension OSInAppMessages {
5032
static var Paused: Bool {
@@ -114,8 +96,8 @@ class UserModelSwiftTests: XCTestCase {
11496
// Triggers
11597
OneSignal.InAppMessages.addTrigger("foo", withValue: "bar")
11698
OneSignal.InAppMessages.addTriggers(["foo": "foo1", "bar": "bar2"])
117-
OneSignal.InAppMessages.removeTrigger(forKey: "foo")
118-
OneSignal.InAppMessages.removeTriggers(forKeys: ["foo", "bar"])
99+
OneSignal.InAppMessages.removeTrigger("foo")
100+
OneSignal.InAppMessages.removeTriggers(["foo", "bar"])
119101
OneSignal.InAppMessages.clearTriggers()
120102

121103
OneSignal.InAppMessages.setClickHandler { action in
@@ -218,4 +200,11 @@ class UserModelSwiftTests: XCTestCase {
218200
OneSignal.InAppMessages.Paused = true
219201
let paused = OneSignal.InAppMessages.Paused
220202
}
203+
204+
func testJWTTokenExpired() {
205+
OneSignal.User.onJwtExpired { externalId, completion in
206+
let newToken = externalId + "newtokenbasedonexternalid"
207+
completion(newToken)
208+
}
209+
}
221210
}

0 commit comments

Comments
 (0)