Skip to content
This repository was archived by the owner on Jun 10, 2025. It is now read-only.

Commit c60617e

Browse files
committed
address comments
1 parent 0ccb99a commit c60617e

File tree

4 files changed

+87
-61
lines changed

4 files changed

+87
-61
lines changed

MSALiOSB2C/Info.plist

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@
2727
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
2828
<key>CFBundleURLSchemes</key>
2929
<array>
30-
<string>msal90c0fe63-bcf2-44d5-8fb7-b8bbc0b29dc6</string>
31-
<string>auth</string>
30+
<string>msauth.com.microsoft.identity.client.sample.MSALiOSB2C</string>
3231
</array>
3332
</dict>
3433
</array>

MSALiOSB2C/MSALiOSB2C.entitlements

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
<dict>
55
<key>keychain-access-groups</key>
66
<array>
7-
<string>$(AppIdentifierPrefix)com.microsoft.identity.client.sample.MSALiOSB2C</string>
87
<string>$(AppIdentifierPrefix)com.microsoft.adalcache</string>
98
</array>
109
</dict>

MSALiOSB2C/ViewController.swift

Lines changed: 84 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class ViewController: UIViewController, UITextFieldDelegate, URLSessionDelegate
4646

4747
var application: MSALPublicClientApplication!
4848

49-
var accessToken = String()
49+
var accessToken: String?
5050

5151
@IBOutlet weak var loggingText: UITextView!
5252
@IBOutlet weak var signoutButton: UIButton!
@@ -62,8 +62,8 @@ class ViewController: UIViewController, UITextFieldDelegate, URLSessionDelegate
6262

6363
Initialize a MSALPublicClientApplication with a MSALPublicClientApplicationConfig.
6464
MSALPublicClientApplicationConfig can be initialized with client id, redirect uri and authority.
65-
Redirect uri will be constucted automatically in the form of "msal<your-client-id-here>://auth" if not provided.
66-
65+
Redirect uri will be constucted automatically in the form of "msauth.<your-bundle-id-here>://auth" if not provided.
66+
The scheme part, i.e. "msauth.<your-bundle-id-here>", needs to be registered in the info.plist of the project
6767
*/
6868

6969
let pcaConfig = MSALPublicClientApplicationConfig(clientId: kClientID)
@@ -92,12 +92,12 @@ class ViewController: UIViewController, UITextFieldDelegate, URLSessionDelegate
9292

9393
*/
9494

95-
let authority = try self.getAuthority(policy: self.kSignupOrSigninPolicy)
95+
let authority = try self.getAuthority(forPolicy: self.kSignupOrSigninPolicy)
9696

9797
/**
98-
Acquire a token for a new user using interactive authentication
98+
Acquire a token for a new account using interactive authentication
9999

100-
- forScopes: Permissions you want included in the access token received
100+
- scopes: Permissions you want included in the access token received
101101
in the result in the completionBlock. Not all scopes are
102102
gauranteed to be included in the access token returned.
103103
- completionBlock: The completion block that will be called when the authentication
@@ -107,9 +107,9 @@ class ViewController: UIViewController, UITextFieldDelegate, URLSessionDelegate
107107
let parameters = MSALInteractiveTokenParameters(scopes: kScopes)
108108
parameters.authority = authority
109109
application.acquireToken(with: parameters) { (result, error) in
110-
if error == nil {
111-
self.accessToken = (result?.accessToken)!
112-
self.loggingText.text = "Access token is \(self.accessToken)"
110+
if let result = result {
111+
self.accessToken = result.accessToken
112+
self.loggingText.text = "Access token is \(self.accessToken ?? "Empty")"
113113
self.signoutButton.isEnabled = true
114114
self.callGraphApiButton.isEnabled = true
115115
self.editProfileButton.isEnabled = true
@@ -137,12 +137,12 @@ class ViewController: UIViewController, UITextFieldDelegate, URLSessionDelegate
137137

138138
*/
139139

140-
let authority = try self.getAuthority(policy: self.kEditProfilePolicy)
140+
let authority = try self.getAuthority(forPolicy: self.kEditProfilePolicy)
141141

142142
/**
143143
Acquire a token for a new account using interactive authentication
144144

145-
- forScopes: Permissions you want included in the access token received
145+
- scopes: Permissions you want included in the access token received
146146
in the result in the completionBlock. Not all scopes are
147147
gauranteed to be included in the access token returned.
148148
- completionBlock: The completion block that will be called when the authentication
@@ -155,12 +155,10 @@ class ViewController: UIViewController, UITextFieldDelegate, URLSessionDelegate
155155
parameters.account = thisAccount
156156

157157
application.acquireToken(with: parameters) { (result, error) in
158-
if error == nil {
159-
self.loggingText.text = "Successfully edited profile"
160-
161-
158+
if let error = error {
159+
self.loggingText.text = "Could not edit profile: \(error)"
162160
} else {
163-
self.loggingText.text = "Could not edit profile: \(error ?? "No error informarion" as! Error)"
161+
self.loggingText.text = "Successfully edited profile"
164162
}
165163
}
166164
} catch {
@@ -181,16 +179,16 @@ class ViewController: UIViewController, UITextFieldDelegate, URLSessionDelegate
181179

182180
*/
183181

184-
let authority = try self.getAuthority(policy: self.kSignupOrSigninPolicy)
182+
let authority = try self.getAuthority(forPolicy: self.kSignupOrSigninPolicy)
185183

186184
/**
187185

188-
Acquire a token for an existing user silently
186+
Acquire a token for an existing account silently
189187

190-
- forScopes: Permissions you want included in the access token received
188+
- scopes: Permissions you want included in the access token received
191189
in the result in the completionBlock. Not all scopes are
192190
gauranteed to be included in the access token returned.
193-
- User: A user object that we retrieved from the application object before that the
191+
- account: An account object that we retrieved from the application object before that the
194192
authentication flow will be locked down to.
195193
- completionBlock: The completion block that will be called when the authentication
196194
flow completes, or encounters an error.
@@ -204,60 +202,83 @@ class ViewController: UIViewController, UITextFieldDelegate, URLSessionDelegate
204202
let parameters = MSALSilentTokenParameters(scopes: kScopes, account:thisAccount)
205203
parameters.authority = authority
206204
self.application.acquireTokenSilent(with: parameters) { (result, error) in
207-
if error == nil {
208-
self.accessToken = (result?.accessToken)!
209-
self.loggingText.text = "Refreshing token silently"
210-
self.loggingText.text = "Refreshed Access token is \(self.accessToken)"
205+
if let error = error {
211206

212-
} else if ((error! as NSError).code == MSALError.interactionRequired.rawValue) {
207+
let nsError = error as NSError
213208

214-
// Notice we supply the user here. This ensures we acquire token for the same user
215-
// as we originally authenticated.
209+
// interactionRequired means we need to ask the user to sign-in. This usually happens
210+
// when the user's Refresh Token is expired or if the user has changed their password
211+
// among other possible reasons.
216212

217-
let parameters = MSALInteractiveTokenParameters(scopes: self.kScopes)
218-
parameters.account = thisAccount
219-
220-
self.application.acquireToken(with: parameters) { (result, error) in
221-
if error == nil {
222-
self.accessToken = (result?.accessToken)!
223-
self.loggingText.text = "Access token is \(self.accessToken)"
213+
if (nsError.domain == MSALErrorDomain) {
214+
215+
if (nsError.code == MSALError.interactionRequired.rawValue) {
216+
217+
// Notice we supply the account here. This ensures we acquire token for the same account
218+
// as we originally authenticated.
224219

225-
} else {
226-
self.loggingText.text = "Could not acquire new token: \(error ?? "No error informarion" as! Error)"
220+
let parameters = MSALInteractiveTokenParameters(scopes: self.kScopes)
221+
parameters.account = thisAccount
222+
223+
self.application.acquireToken(with: parameters) { (result, error) in
224+
if let result = result {
225+
self.accessToken = result.accessToken
226+
self.loggingText.text = "Access token is \(self.accessToken ?? "empty")"
227+
228+
} else {
229+
self.loggingText.text = "Could not acquire new token: \(error ?? "No error informarion" as! Error)"
230+
}
231+
}
232+
return
227233
}
228234
}
229-
} else {
230-
self.loggingText.text = "Could not acquire token: \(error ?? "No error informarion" as! Error)"
235+
236+
self.loggingText.text = "Could not acquire token: \(error)"
237+
return
231238
}
239+
240+
guard let result = result else {
241+
242+
self.loggingText.text = "Could not acquire token: No result returned"
243+
return
244+
}
245+
246+
self.accessToken = result.accessToken
247+
self.loggingText.text = "Refreshing token silently"
248+
self.loggingText.text = "Refreshed access token is \(self.accessToken ?? "empty")"
232249
}
233250
} catch {
234251
self.loggingText.text = "Unable to construct parameters before calling acquire token \(error)"
235252
}
236253
}
237254

238255
@IBAction func callApi(_ sender: UIButton) {
239-
256+
guard let accessToken = self.accessToken else {
257+
self.loggingText.text = "Operation failed because could not find an access token!"
258+
return
259+
}
240260

241261
let sessionConfig = URLSessionConfiguration.default
242262
let url = URL(string: self.kGraphURI)
243263
var request = URLRequest(url: url!)
244-
request.setValue("Bearer \(self.accessToken)", forHTTPHeaderField: "Authorization")
264+
request.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
245265
let urlSession = URLSession(configuration: sessionConfig, delegate: self, delegateQueue: OperationQueue.main)
246266

247267
urlSession.dataTask(with: request) { data, response, error in
248-
249-
if error == nil {
250-
let result = try? JSONSerialization.jsonObject(with: data!, options: [])
251-
if result != nil {
252-
self.loggingText.text = "API response: \(result.debugDescription)"
253-
} else {
254-
self.loggingText.text = "Nothing returned from API"
255-
}
256-
} else {
268+
guard let validData = data else {
257269
self.loggingText.text = "Could not call API: \(error ?? "No error informarion" as! Error)"
270+
return
271+
}
272+
273+
let result = try? JSONSerialization.jsonObject(with: validData, options: [])
274+
275+
guard let validResult = result as? [String: Any] else {
276+
self.loggingText.text = "Nothing returned from API"
277+
return
258278
}
279+
280+
self.loggingText.text = "API response: \(validResult.debugDescription)"
259281
}.resume()
260-
261282
}
262283

263284
@IBAction func signoutButton(_ sender: UIButton) {
@@ -272,6 +293,8 @@ class ViewController: UIViewController, UITextFieldDelegate, URLSessionDelegate
272293

273294
if let accountToRemove = thisAccount {
274295
try application.remove(accountToRemove)
296+
} else {
297+
self.loggingText.text = "There is no account to signing out!"
275298
}
276299

277300
self.signoutButton.isEnabled = false
@@ -291,19 +314,24 @@ class ViewController: UIViewController, UITextFieldDelegate, URLSessionDelegate
291314

292315
override func viewWillAppear(_ animated: Bool) {
293316

294-
if self.accessToken.isEmpty {
317+
if self.accessToken == nil {
295318
signoutButton.isEnabled = false
296319
callGraphApiButton.isEnabled = false
297320
editProfileButton.isEnabled = false
298321
refreshTokenButton.isEnabled = false
299322
}
300323
}
301324

302-
func getAccountByPolicy (withAccounts: [MSALAccount], policy: String) throws -> MSALAccount? {
325+
func getAccountByPolicy (withAccounts accounts: [MSALAccount], policy: String) throws -> MSALAccount? {
303326

304-
for account in withAccounts {
305-
if (account.homeAccountId != nil && account.homeAccountId!.objectId!.hasSuffix(policy.lowercased())) {
306-
return account
327+
for account in accounts {
328+
// This is a single account sample, so we only check the suffic part of the object id,
329+
// where object id is in the form of <object id>-<policy>.
330+
// For multi-account apps, the whole object id needs to be checked.
331+
if let homeAccountId = account.homeAccountId, let objectId = homeAccountId.objectId {
332+
if objectId.hasSuffix(policy.lowercased()) {
333+
return account
334+
}
307335
}
308336
}
309337
return nil
@@ -318,7 +346,7 @@ class ViewController: UIViewController, UITextFieldDelegate, URLSessionDelegate
318346
tenant, such as contoso.onmicrosoft.com), and `<policy>` is the policy you wish to
319347
use for the current user flow.
320348
*/
321-
func getAuthority(policy: String) throws -> MSALB2CAuthority {
349+
func getAuthority(forPolicy policy: String) throws -> MSALB2CAuthority {
322350
guard let authorityURL = URL(string: String(format: self.kEndpoint, self.kTenantName, policy)) else {
323351
throw NSError(domain: "SomeDomain",
324352
code: 1,

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ The MSAL preview library for iOS and macOS gives your app the ability to begin u
2222
```Swift
2323
do {
2424
// Create an instance of MSALPublicClientApplication with proper config
25-
let authority = try MSALB2CAuthority.init(url: URL(string:kAuthority)!)
26-
let pcaConfig = MSALPublicClientApplicationConfig.init(clientId: <your-client-id-here>, redirectUri: nil, authority: authority)
25+
let authority = try MSALB2CAuthority(url: URL(string:kAuthority)!)
26+
let pcaConfig = MSALPublicClientApplicationConfig(clientId: <your-client-id-here>, redirectUri: nil, authority: authority)
2727
let application = try MSALPublicClientApplication(configuration: pcaConfig)
2828

2929
application.acquireToken(forScopes: kScopes) { (result, error) in

0 commit comments

Comments
 (0)