MSAL - Failed to set item into keychain when trying to authenticate Microsoft Graph login










0















I am trying to integrate with Microsoft Graph in my iOS application. I am developing in Swift on XCode. I followed this tutorial:



https://docs.microsoft.com/en-us/azure/active-directory/develop/tutorial-v2-ios#register-your-application



When I click connect, enter my login details, It keeps giving me the error message below. I have tried debugging and it goes into the acquireTokenInteractively() and the error is printed.



enter image description here
I have registered my application on the Microsoft app portal, enabled keychain sharing on the capabilities tab of the application etc, not really sure why this won't work..

thanks for any help.



import UIKit
import MSAL

class ViewController: UIViewController, UITextFieldDelegate, URLSessionDelegate

// Update the below to your client ID you received in the portal. The below is for running the demo only
let kClientID = "a88969f1-61c7-4322-a9a0-9212bb96b782"

// These settings you don't need to edit unless you wish to attempt deeper scenarios with the app.
let kGraphURI = "https://graph.microsoft.com/v1.0/me/"
//let kScopes: [String] = ["https://graph.microsoft.com/user.read"]
let kAuthority = "https://login.microsoftonline.com/common"

var accessToken = String()
var applicationContext : MSALPublicClientApplication?

@IBOutlet weak var connectButton: UIButton!
@IBOutlet weak var signoutButton: UIButton!
@IBOutlet weak var loggingText: UITextView!

@IBAction func connectButtonTapped(_ sender: UIButton)
print("Connect button tapped")
if self.currentAccount() == nil
// We check to see if we have a current logged in account.
// If we don't, then we need to sign someone in.
self.acquireTokenInteractively()
else
self.acquireTokenSilently()




@IBAction func signoutButtonTapped(_ sender: UIButton)
print("Signout button tapped")
guard let applicationContext = self.applicationContext else return

guard let account = self.currentAccount() else return

do

/**
Removes all tokens from the cache for this application for the provided account
- account: The account to remove from the cache
*/

try applicationContext.remove(account)
self.loggingText.text = ""
self.signoutButton.isEnabled = false

catch let error as NSError

self.loggingText.text = "Received error signing account out: (error)"



/**
Setup public client application in viewDidLoad
*/

override func viewDidLoad()

super.viewDidLoad()

do

/**
Initialize a MSALPublicClientApplication with a given clientID and authority
- clientId: The clientID of your application, you should get this from the app portal.
- authority: A URL indicating a directory that MSAL can use to obtain tokens. In Azure AD
it is of the form https://<instance/<tenant>, where <instance> is the
directory host (e.g. https://login.microsoftonline.com) and <tenant> is a
identifier within the directory itself (e.g. a domain associated to the
tenant, such as contoso.onmicrosoft.com, or the GUID representing the
TenantID property of the directory)
- error The error that occurred creating the application object, if any, if you're
not interested in the specific error pass in nil.
*/

guard let authorityURL = URL(string: kAuthority) else
self.loggingText.text = "Unable to create authority URL"
return


let authority = try MSALAuthority(url: authorityURL)
self.applicationContext = try MSALPublicClientApplication(clientId: kClientID, authority: authority)

catch let error
self.loggingText.text = "Unable to create Application Context (error)"



override func viewWillAppear(_ animated: Bool)

super.viewWillAppear(animated)
signoutButton.isEnabled = !self.accessToken.isEmpty


/**
This button will invoke the authorization flow.
*/

@IBAction func callGraphButton(_ sender: UIButton)

if self.currentAccount() == nil
// We check to see if we have a current logged in account.
// If we don't, then we need to sign someone in.
self.acquireTokenInteractively()
else
self.acquireTokenSilently()



func getContentWithToken()

// Specify the Graph API endpoint
let url = URL(string: kGraphURI)
var request = URLRequest(url: url!)

// Set the Authorization header for the request. We use Bearer tokens, so we specify Bearer + the token we got from the result
request.setValue("Bearer (self.accessToken)", forHTTPHeaderField: "Authorization")

URLSession.shared.dataTask(with: request) data, response, error in

if let error = error
self.loggingText.text = "Couldn't get graph result: (error)"
return


guard let result = try? JSONSerialization.jsonObject(with: data!, options: ) else

self.loggingText.text = "Couldn't deserialize result JSON"
return


self.loggingText.text = "Result from Graph: (result))"

.resume()


func acquireTokenInteractively()

guard let applicationContext = self.applicationContext else return

applicationContext.acquireToken(forScopes: ApplicationConstants.kScopes) (result, error) in

if let error = error
self.loggingText.text = "Could not acquire token: (error)"
return


guard let result = result else

self.loggingText.text = "Could not acquire token: No result returned"
return


self.accessToken = result.accessToken
self.loggingText.text = "Access token is (self.accessToken)"
self.signoutButton.isEnabled = true
self.getContentWithToken()



func acquireTokenSilently()

guard let applicationContext = self.applicationContext else return

/**
Acquire a token for an existing account silently
- forScopes: Permissions you want included in the access token received
in the result in the completionBlock. Not all scopes are
guaranteed to be included in the access token returned.
- account: An account object that we retrieved from the application object before that the
authentication flow will be locked down to.
- completionBlock: The completion block that will be called when the authentication
flow completes, or encounters an error.
*/

applicationContext.acquireTokenSilent(forScopes: ApplicationConstants.kScopes, account: self.currentAccount()!) (result, error) in

if let error = error

let nsError = error as NSError

// interactionRequired means we need to ask the user to sign-in. This usually happens
// when the user's Refresh Token is expired or if the user has changed their password
// among other possible reasons.
if (nsError.domain == MSALErrorDomain
&& nsError.code == MSALErrorCode.interactionRequired.rawValue)

DispatchQueue.main.async
self.acquireTokenInteractively()


else
self.loggingText.text = "Could not acquire token silently: (error)"


return


guard let result = result else

self.loggingText.text = "Could not acquire token: No result returned"
return


self.accessToken = result.accessToken
self.loggingText.text = "Refreshed Access token is (self.accessToken)"
self.signoutButton.isEnabled = true
self.getContentWithToken()



func currentAccount() -> MSALAccount?

guard let applicationContext = self.applicationContext else return nil

// We retrieve our current account by getting the first account from cache
// In multi-account applications, account should be retrieved by home account identifier or username instead
do

let cachedAccounts = try applicationContext.allAccounts()

if !cachedAccounts.isEmpty
return cachedAccounts.first


catch let error as NSError

self.loggingText.text = "Didn't find any accounts in cache: (error)"


return nil




//

struct ApplicationConstants
static let ResourceId = "https://graph.microsoft.com"
static let kAuthority = "https://login.microsoftonline.com/common/oauth2/v2.0"
static let kGraphURI = "https://graph.microsoft.com/v1.0/me/"
static let kScopes = ["https://graph.microsoft.com/Mail.ReadWrite",
"https://graph.microsoft.com/Mail.Send",
"https://graph.microsoft.com/Files.ReadWrite",
"https://graph.microsoft.com/User.ReadBasic.All"]
static var kClientID = "6d5a8e6d-0281-4003-8feb-43a9ca39d4d2"

enum MSGraphError: Error
case nsErrorType(error: NSError)











share|improve this question



















  • 1





    The error code indicates that you haven't correctly added the adalcache keychain sharing item

    – Paulw11
    Nov 14 '18 at 11:59











  • This problem is also referenced specifically here github.com/AzureAD/microsoft-authentication-library-for-objc/…

    – Paulw11
    Nov 14 '18 at 12:06











  • Any solutions for this?

    – Liam
    Nov 14 '18 at 12:48







  • 1





    As well as enabling keychain sharing, did you add com.microsoft.adalcache as a keychain identifier?

    – Paulw11
    Nov 14 '18 at 18:34











  • @Paulw11 that fixed it.. couldn't see that part of configuration on any of the steps in the documentation available! Thanks..

    – Liam
    Nov 14 '18 at 23:56















0















I am trying to integrate with Microsoft Graph in my iOS application. I am developing in Swift on XCode. I followed this tutorial:



https://docs.microsoft.com/en-us/azure/active-directory/develop/tutorial-v2-ios#register-your-application



When I click connect, enter my login details, It keeps giving me the error message below. I have tried debugging and it goes into the acquireTokenInteractively() and the error is printed.



enter image description here
I have registered my application on the Microsoft app portal, enabled keychain sharing on the capabilities tab of the application etc, not really sure why this won't work..

thanks for any help.



import UIKit
import MSAL

class ViewController: UIViewController, UITextFieldDelegate, URLSessionDelegate

// Update the below to your client ID you received in the portal. The below is for running the demo only
let kClientID = "a88969f1-61c7-4322-a9a0-9212bb96b782"

// These settings you don't need to edit unless you wish to attempt deeper scenarios with the app.
let kGraphURI = "https://graph.microsoft.com/v1.0/me/"
//let kScopes: [String] = ["https://graph.microsoft.com/user.read"]
let kAuthority = "https://login.microsoftonline.com/common"

var accessToken = String()
var applicationContext : MSALPublicClientApplication?

@IBOutlet weak var connectButton: UIButton!
@IBOutlet weak var signoutButton: UIButton!
@IBOutlet weak var loggingText: UITextView!

@IBAction func connectButtonTapped(_ sender: UIButton)
print("Connect button tapped")
if self.currentAccount() == nil
// We check to see if we have a current logged in account.
// If we don't, then we need to sign someone in.
self.acquireTokenInteractively()
else
self.acquireTokenSilently()




@IBAction func signoutButtonTapped(_ sender: UIButton)
print("Signout button tapped")
guard let applicationContext = self.applicationContext else return

guard let account = self.currentAccount() else return

do

/**
Removes all tokens from the cache for this application for the provided account
- account: The account to remove from the cache
*/

try applicationContext.remove(account)
self.loggingText.text = ""
self.signoutButton.isEnabled = false

catch let error as NSError

self.loggingText.text = "Received error signing account out: (error)"



/**
Setup public client application in viewDidLoad
*/

override func viewDidLoad()

super.viewDidLoad()

do

/**
Initialize a MSALPublicClientApplication with a given clientID and authority
- clientId: The clientID of your application, you should get this from the app portal.
- authority: A URL indicating a directory that MSAL can use to obtain tokens. In Azure AD
it is of the form https://<instance/<tenant>, where <instance> is the
directory host (e.g. https://login.microsoftonline.com) and <tenant> is a
identifier within the directory itself (e.g. a domain associated to the
tenant, such as contoso.onmicrosoft.com, or the GUID representing the
TenantID property of the directory)
- error The error that occurred creating the application object, if any, if you're
not interested in the specific error pass in nil.
*/

guard let authorityURL = URL(string: kAuthority) else
self.loggingText.text = "Unable to create authority URL"
return


let authority = try MSALAuthority(url: authorityURL)
self.applicationContext = try MSALPublicClientApplication(clientId: kClientID, authority: authority)

catch let error
self.loggingText.text = "Unable to create Application Context (error)"



override func viewWillAppear(_ animated: Bool)

super.viewWillAppear(animated)
signoutButton.isEnabled = !self.accessToken.isEmpty


/**
This button will invoke the authorization flow.
*/

@IBAction func callGraphButton(_ sender: UIButton)

if self.currentAccount() == nil
// We check to see if we have a current logged in account.
// If we don't, then we need to sign someone in.
self.acquireTokenInteractively()
else
self.acquireTokenSilently()



func getContentWithToken()

// Specify the Graph API endpoint
let url = URL(string: kGraphURI)
var request = URLRequest(url: url!)

// Set the Authorization header for the request. We use Bearer tokens, so we specify Bearer + the token we got from the result
request.setValue("Bearer (self.accessToken)", forHTTPHeaderField: "Authorization")

URLSession.shared.dataTask(with: request) data, response, error in

if let error = error
self.loggingText.text = "Couldn't get graph result: (error)"
return


guard let result = try? JSONSerialization.jsonObject(with: data!, options: ) else

self.loggingText.text = "Couldn't deserialize result JSON"
return


self.loggingText.text = "Result from Graph: (result))"

.resume()


func acquireTokenInteractively()

guard let applicationContext = self.applicationContext else return

applicationContext.acquireToken(forScopes: ApplicationConstants.kScopes) (result, error) in

if let error = error
self.loggingText.text = "Could not acquire token: (error)"
return


guard let result = result else

self.loggingText.text = "Could not acquire token: No result returned"
return


self.accessToken = result.accessToken
self.loggingText.text = "Access token is (self.accessToken)"
self.signoutButton.isEnabled = true
self.getContentWithToken()



func acquireTokenSilently()

guard let applicationContext = self.applicationContext else return

/**
Acquire a token for an existing account silently
- forScopes: Permissions you want included in the access token received
in the result in the completionBlock. Not all scopes are
guaranteed to be included in the access token returned.
- account: An account object that we retrieved from the application object before that the
authentication flow will be locked down to.
- completionBlock: The completion block that will be called when the authentication
flow completes, or encounters an error.
*/

applicationContext.acquireTokenSilent(forScopes: ApplicationConstants.kScopes, account: self.currentAccount()!) (result, error) in

if let error = error

let nsError = error as NSError

// interactionRequired means we need to ask the user to sign-in. This usually happens
// when the user's Refresh Token is expired or if the user has changed their password
// among other possible reasons.
if (nsError.domain == MSALErrorDomain
&& nsError.code == MSALErrorCode.interactionRequired.rawValue)

DispatchQueue.main.async
self.acquireTokenInteractively()


else
self.loggingText.text = "Could not acquire token silently: (error)"


return


guard let result = result else

self.loggingText.text = "Could not acquire token: No result returned"
return


self.accessToken = result.accessToken
self.loggingText.text = "Refreshed Access token is (self.accessToken)"
self.signoutButton.isEnabled = true
self.getContentWithToken()



func currentAccount() -> MSALAccount?

guard let applicationContext = self.applicationContext else return nil

// We retrieve our current account by getting the first account from cache
// In multi-account applications, account should be retrieved by home account identifier or username instead
do

let cachedAccounts = try applicationContext.allAccounts()

if !cachedAccounts.isEmpty
return cachedAccounts.first


catch let error as NSError

self.loggingText.text = "Didn't find any accounts in cache: (error)"


return nil




//

struct ApplicationConstants
static let ResourceId = "https://graph.microsoft.com"
static let kAuthority = "https://login.microsoftonline.com/common/oauth2/v2.0"
static let kGraphURI = "https://graph.microsoft.com/v1.0/me/"
static let kScopes = ["https://graph.microsoft.com/Mail.ReadWrite",
"https://graph.microsoft.com/Mail.Send",
"https://graph.microsoft.com/Files.ReadWrite",
"https://graph.microsoft.com/User.ReadBasic.All"]
static var kClientID = "6d5a8e6d-0281-4003-8feb-43a9ca39d4d2"

enum MSGraphError: Error
case nsErrorType(error: NSError)











share|improve this question



















  • 1





    The error code indicates that you haven't correctly added the adalcache keychain sharing item

    – Paulw11
    Nov 14 '18 at 11:59











  • This problem is also referenced specifically here github.com/AzureAD/microsoft-authentication-library-for-objc/…

    – Paulw11
    Nov 14 '18 at 12:06











  • Any solutions for this?

    – Liam
    Nov 14 '18 at 12:48







  • 1





    As well as enabling keychain sharing, did you add com.microsoft.adalcache as a keychain identifier?

    – Paulw11
    Nov 14 '18 at 18:34











  • @Paulw11 that fixed it.. couldn't see that part of configuration on any of the steps in the documentation available! Thanks..

    – Liam
    Nov 14 '18 at 23:56













0












0








0








I am trying to integrate with Microsoft Graph in my iOS application. I am developing in Swift on XCode. I followed this tutorial:



https://docs.microsoft.com/en-us/azure/active-directory/develop/tutorial-v2-ios#register-your-application



When I click connect, enter my login details, It keeps giving me the error message below. I have tried debugging and it goes into the acquireTokenInteractively() and the error is printed.



enter image description here
I have registered my application on the Microsoft app portal, enabled keychain sharing on the capabilities tab of the application etc, not really sure why this won't work..

thanks for any help.



import UIKit
import MSAL

class ViewController: UIViewController, UITextFieldDelegate, URLSessionDelegate

// Update the below to your client ID you received in the portal. The below is for running the demo only
let kClientID = "a88969f1-61c7-4322-a9a0-9212bb96b782"

// These settings you don't need to edit unless you wish to attempt deeper scenarios with the app.
let kGraphURI = "https://graph.microsoft.com/v1.0/me/"
//let kScopes: [String] = ["https://graph.microsoft.com/user.read"]
let kAuthority = "https://login.microsoftonline.com/common"

var accessToken = String()
var applicationContext : MSALPublicClientApplication?

@IBOutlet weak var connectButton: UIButton!
@IBOutlet weak var signoutButton: UIButton!
@IBOutlet weak var loggingText: UITextView!

@IBAction func connectButtonTapped(_ sender: UIButton)
print("Connect button tapped")
if self.currentAccount() == nil
// We check to see if we have a current logged in account.
// If we don't, then we need to sign someone in.
self.acquireTokenInteractively()
else
self.acquireTokenSilently()




@IBAction func signoutButtonTapped(_ sender: UIButton)
print("Signout button tapped")
guard let applicationContext = self.applicationContext else return

guard let account = self.currentAccount() else return

do

/**
Removes all tokens from the cache for this application for the provided account
- account: The account to remove from the cache
*/

try applicationContext.remove(account)
self.loggingText.text = ""
self.signoutButton.isEnabled = false

catch let error as NSError

self.loggingText.text = "Received error signing account out: (error)"



/**
Setup public client application in viewDidLoad
*/

override func viewDidLoad()

super.viewDidLoad()

do

/**
Initialize a MSALPublicClientApplication with a given clientID and authority
- clientId: The clientID of your application, you should get this from the app portal.
- authority: A URL indicating a directory that MSAL can use to obtain tokens. In Azure AD
it is of the form https://<instance/<tenant>, where <instance> is the
directory host (e.g. https://login.microsoftonline.com) and <tenant> is a
identifier within the directory itself (e.g. a domain associated to the
tenant, such as contoso.onmicrosoft.com, or the GUID representing the
TenantID property of the directory)
- error The error that occurred creating the application object, if any, if you're
not interested in the specific error pass in nil.
*/

guard let authorityURL = URL(string: kAuthority) else
self.loggingText.text = "Unable to create authority URL"
return


let authority = try MSALAuthority(url: authorityURL)
self.applicationContext = try MSALPublicClientApplication(clientId: kClientID, authority: authority)

catch let error
self.loggingText.text = "Unable to create Application Context (error)"



override func viewWillAppear(_ animated: Bool)

super.viewWillAppear(animated)
signoutButton.isEnabled = !self.accessToken.isEmpty


/**
This button will invoke the authorization flow.
*/

@IBAction func callGraphButton(_ sender: UIButton)

if self.currentAccount() == nil
// We check to see if we have a current logged in account.
// If we don't, then we need to sign someone in.
self.acquireTokenInteractively()
else
self.acquireTokenSilently()



func getContentWithToken()

// Specify the Graph API endpoint
let url = URL(string: kGraphURI)
var request = URLRequest(url: url!)

// Set the Authorization header for the request. We use Bearer tokens, so we specify Bearer + the token we got from the result
request.setValue("Bearer (self.accessToken)", forHTTPHeaderField: "Authorization")

URLSession.shared.dataTask(with: request) data, response, error in

if let error = error
self.loggingText.text = "Couldn't get graph result: (error)"
return


guard let result = try? JSONSerialization.jsonObject(with: data!, options: ) else

self.loggingText.text = "Couldn't deserialize result JSON"
return


self.loggingText.text = "Result from Graph: (result))"

.resume()


func acquireTokenInteractively()

guard let applicationContext = self.applicationContext else return

applicationContext.acquireToken(forScopes: ApplicationConstants.kScopes) (result, error) in

if let error = error
self.loggingText.text = "Could not acquire token: (error)"
return


guard let result = result else

self.loggingText.text = "Could not acquire token: No result returned"
return


self.accessToken = result.accessToken
self.loggingText.text = "Access token is (self.accessToken)"
self.signoutButton.isEnabled = true
self.getContentWithToken()



func acquireTokenSilently()

guard let applicationContext = self.applicationContext else return

/**
Acquire a token for an existing account silently
- forScopes: Permissions you want included in the access token received
in the result in the completionBlock. Not all scopes are
guaranteed to be included in the access token returned.
- account: An account object that we retrieved from the application object before that the
authentication flow will be locked down to.
- completionBlock: The completion block that will be called when the authentication
flow completes, or encounters an error.
*/

applicationContext.acquireTokenSilent(forScopes: ApplicationConstants.kScopes, account: self.currentAccount()!) (result, error) in

if let error = error

let nsError = error as NSError

// interactionRequired means we need to ask the user to sign-in. This usually happens
// when the user's Refresh Token is expired or if the user has changed their password
// among other possible reasons.
if (nsError.domain == MSALErrorDomain
&& nsError.code == MSALErrorCode.interactionRequired.rawValue)

DispatchQueue.main.async
self.acquireTokenInteractively()


else
self.loggingText.text = "Could not acquire token silently: (error)"


return


guard let result = result else

self.loggingText.text = "Could not acquire token: No result returned"
return


self.accessToken = result.accessToken
self.loggingText.text = "Refreshed Access token is (self.accessToken)"
self.signoutButton.isEnabled = true
self.getContentWithToken()



func currentAccount() -> MSALAccount?

guard let applicationContext = self.applicationContext else return nil

// We retrieve our current account by getting the first account from cache
// In multi-account applications, account should be retrieved by home account identifier or username instead
do

let cachedAccounts = try applicationContext.allAccounts()

if !cachedAccounts.isEmpty
return cachedAccounts.first


catch let error as NSError

self.loggingText.text = "Didn't find any accounts in cache: (error)"


return nil




//

struct ApplicationConstants
static let ResourceId = "https://graph.microsoft.com"
static let kAuthority = "https://login.microsoftonline.com/common/oauth2/v2.0"
static let kGraphURI = "https://graph.microsoft.com/v1.0/me/"
static let kScopes = ["https://graph.microsoft.com/Mail.ReadWrite",
"https://graph.microsoft.com/Mail.Send",
"https://graph.microsoft.com/Files.ReadWrite",
"https://graph.microsoft.com/User.ReadBasic.All"]
static var kClientID = "6d5a8e6d-0281-4003-8feb-43a9ca39d4d2"

enum MSGraphError: Error
case nsErrorType(error: NSError)











share|improve this question
















I am trying to integrate with Microsoft Graph in my iOS application. I am developing in Swift on XCode. I followed this tutorial:



https://docs.microsoft.com/en-us/azure/active-directory/develop/tutorial-v2-ios#register-your-application



When I click connect, enter my login details, It keeps giving me the error message below. I have tried debugging and it goes into the acquireTokenInteractively() and the error is printed.



enter image description here
I have registered my application on the Microsoft app portal, enabled keychain sharing on the capabilities tab of the application etc, not really sure why this won't work..

thanks for any help.



import UIKit
import MSAL

class ViewController: UIViewController, UITextFieldDelegate, URLSessionDelegate

// Update the below to your client ID you received in the portal. The below is for running the demo only
let kClientID = "a88969f1-61c7-4322-a9a0-9212bb96b782"

// These settings you don't need to edit unless you wish to attempt deeper scenarios with the app.
let kGraphURI = "https://graph.microsoft.com/v1.0/me/"
//let kScopes: [String] = ["https://graph.microsoft.com/user.read"]
let kAuthority = "https://login.microsoftonline.com/common"

var accessToken = String()
var applicationContext : MSALPublicClientApplication?

@IBOutlet weak var connectButton: UIButton!
@IBOutlet weak var signoutButton: UIButton!
@IBOutlet weak var loggingText: UITextView!

@IBAction func connectButtonTapped(_ sender: UIButton)
print("Connect button tapped")
if self.currentAccount() == nil
// We check to see if we have a current logged in account.
// If we don't, then we need to sign someone in.
self.acquireTokenInteractively()
else
self.acquireTokenSilently()




@IBAction func signoutButtonTapped(_ sender: UIButton)
print("Signout button tapped")
guard let applicationContext = self.applicationContext else return

guard let account = self.currentAccount() else return

do

/**
Removes all tokens from the cache for this application for the provided account
- account: The account to remove from the cache
*/

try applicationContext.remove(account)
self.loggingText.text = ""
self.signoutButton.isEnabled = false

catch let error as NSError

self.loggingText.text = "Received error signing account out: (error)"



/**
Setup public client application in viewDidLoad
*/

override func viewDidLoad()

super.viewDidLoad()

do

/**
Initialize a MSALPublicClientApplication with a given clientID and authority
- clientId: The clientID of your application, you should get this from the app portal.
- authority: A URL indicating a directory that MSAL can use to obtain tokens. In Azure AD
it is of the form https://<instance/<tenant>, where <instance> is the
directory host (e.g. https://login.microsoftonline.com) and <tenant> is a
identifier within the directory itself (e.g. a domain associated to the
tenant, such as contoso.onmicrosoft.com, or the GUID representing the
TenantID property of the directory)
- error The error that occurred creating the application object, if any, if you're
not interested in the specific error pass in nil.
*/

guard let authorityURL = URL(string: kAuthority) else
self.loggingText.text = "Unable to create authority URL"
return


let authority = try MSALAuthority(url: authorityURL)
self.applicationContext = try MSALPublicClientApplication(clientId: kClientID, authority: authority)

catch let error
self.loggingText.text = "Unable to create Application Context (error)"



override func viewWillAppear(_ animated: Bool)

super.viewWillAppear(animated)
signoutButton.isEnabled = !self.accessToken.isEmpty


/**
This button will invoke the authorization flow.
*/

@IBAction func callGraphButton(_ sender: UIButton)

if self.currentAccount() == nil
// We check to see if we have a current logged in account.
// If we don't, then we need to sign someone in.
self.acquireTokenInteractively()
else
self.acquireTokenSilently()



func getContentWithToken()

// Specify the Graph API endpoint
let url = URL(string: kGraphURI)
var request = URLRequest(url: url!)

// Set the Authorization header for the request. We use Bearer tokens, so we specify Bearer + the token we got from the result
request.setValue("Bearer (self.accessToken)", forHTTPHeaderField: "Authorization")

URLSession.shared.dataTask(with: request) data, response, error in

if let error = error
self.loggingText.text = "Couldn't get graph result: (error)"
return


guard let result = try? JSONSerialization.jsonObject(with: data!, options: ) else

self.loggingText.text = "Couldn't deserialize result JSON"
return


self.loggingText.text = "Result from Graph: (result))"

.resume()


func acquireTokenInteractively()

guard let applicationContext = self.applicationContext else return

applicationContext.acquireToken(forScopes: ApplicationConstants.kScopes) (result, error) in

if let error = error
self.loggingText.text = "Could not acquire token: (error)"
return


guard let result = result else

self.loggingText.text = "Could not acquire token: No result returned"
return


self.accessToken = result.accessToken
self.loggingText.text = "Access token is (self.accessToken)"
self.signoutButton.isEnabled = true
self.getContentWithToken()



func acquireTokenSilently()

guard let applicationContext = self.applicationContext else return

/**
Acquire a token for an existing account silently
- forScopes: Permissions you want included in the access token received
in the result in the completionBlock. Not all scopes are
guaranteed to be included in the access token returned.
- account: An account object that we retrieved from the application object before that the
authentication flow will be locked down to.
- completionBlock: The completion block that will be called when the authentication
flow completes, or encounters an error.
*/

applicationContext.acquireTokenSilent(forScopes: ApplicationConstants.kScopes, account: self.currentAccount()!) (result, error) in

if let error = error

let nsError = error as NSError

// interactionRequired means we need to ask the user to sign-in. This usually happens
// when the user's Refresh Token is expired or if the user has changed their password
// among other possible reasons.
if (nsError.domain == MSALErrorDomain
&& nsError.code == MSALErrorCode.interactionRequired.rawValue)

DispatchQueue.main.async
self.acquireTokenInteractively()


else
self.loggingText.text = "Could not acquire token silently: (error)"


return


guard let result = result else

self.loggingText.text = "Could not acquire token: No result returned"
return


self.accessToken = result.accessToken
self.loggingText.text = "Refreshed Access token is (self.accessToken)"
self.signoutButton.isEnabled = true
self.getContentWithToken()



func currentAccount() -> MSALAccount?

guard let applicationContext = self.applicationContext else return nil

// We retrieve our current account by getting the first account from cache
// In multi-account applications, account should be retrieved by home account identifier or username instead
do

let cachedAccounts = try applicationContext.allAccounts()

if !cachedAccounts.isEmpty
return cachedAccounts.first


catch let error as NSError

self.loggingText.text = "Didn't find any accounts in cache: (error)"


return nil




//

struct ApplicationConstants
static let ResourceId = "https://graph.microsoft.com"
static let kAuthority = "https://login.microsoftonline.com/common/oauth2/v2.0"
static let kGraphURI = "https://graph.microsoft.com/v1.0/me/"
static let kScopes = ["https://graph.microsoft.com/Mail.ReadWrite",
"https://graph.microsoft.com/Mail.Send",
"https://graph.microsoft.com/Files.ReadWrite",
"https://graph.microsoft.com/User.ReadBasic.All"]
static var kClientID = "6d5a8e6d-0281-4003-8feb-43a9ca39d4d2"

enum MSGraphError: Error
case nsErrorType(error: NSError)








ios xcode microsoft-graph keychain msal






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 14 '18 at 11:12







Liam

















asked Nov 14 '18 at 10:49









LiamLiam

120114




120114







  • 1





    The error code indicates that you haven't correctly added the adalcache keychain sharing item

    – Paulw11
    Nov 14 '18 at 11:59











  • This problem is also referenced specifically here github.com/AzureAD/microsoft-authentication-library-for-objc/…

    – Paulw11
    Nov 14 '18 at 12:06











  • Any solutions for this?

    – Liam
    Nov 14 '18 at 12:48







  • 1





    As well as enabling keychain sharing, did you add com.microsoft.adalcache as a keychain identifier?

    – Paulw11
    Nov 14 '18 at 18:34











  • @Paulw11 that fixed it.. couldn't see that part of configuration on any of the steps in the documentation available! Thanks..

    – Liam
    Nov 14 '18 at 23:56












  • 1





    The error code indicates that you haven't correctly added the adalcache keychain sharing item

    – Paulw11
    Nov 14 '18 at 11:59











  • This problem is also referenced specifically here github.com/AzureAD/microsoft-authentication-library-for-objc/…

    – Paulw11
    Nov 14 '18 at 12:06











  • Any solutions for this?

    – Liam
    Nov 14 '18 at 12:48







  • 1





    As well as enabling keychain sharing, did you add com.microsoft.adalcache as a keychain identifier?

    – Paulw11
    Nov 14 '18 at 18:34











  • @Paulw11 that fixed it.. couldn't see that part of configuration on any of the steps in the documentation available! Thanks..

    – Liam
    Nov 14 '18 at 23:56







1




1





The error code indicates that you haven't correctly added the adalcache keychain sharing item

– Paulw11
Nov 14 '18 at 11:59





The error code indicates that you haven't correctly added the adalcache keychain sharing item

– Paulw11
Nov 14 '18 at 11:59













This problem is also referenced specifically here github.com/AzureAD/microsoft-authentication-library-for-objc/…

– Paulw11
Nov 14 '18 at 12:06





This problem is also referenced specifically here github.com/AzureAD/microsoft-authentication-library-for-objc/…

– Paulw11
Nov 14 '18 at 12:06













Any solutions for this?

– Liam
Nov 14 '18 at 12:48






Any solutions for this?

– Liam
Nov 14 '18 at 12:48





1




1





As well as enabling keychain sharing, did you add com.microsoft.adalcache as a keychain identifier?

– Paulw11
Nov 14 '18 at 18:34





As well as enabling keychain sharing, did you add com.microsoft.adalcache as a keychain identifier?

– Paulw11
Nov 14 '18 at 18:34













@Paulw11 that fixed it.. couldn't see that part of configuration on any of the steps in the documentation available! Thanks..

– Liam
Nov 14 '18 at 23:56





@Paulw11 that fixed it.. couldn't see that part of configuration on any of the steps in the documentation available! Thanks..

– Liam
Nov 14 '18 at 23:56












1 Answer
1






active

oldest

votes


















0














You need to ensure you have added the correct identifier to your keychain sharing group. The default value is com.microsoft.adalcache.






share|improve this answer






















    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53298417%2fmsal-failed-to-set-item-into-keychain-when-trying-to-authenticate-microsoft-gr%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    0














    You need to ensure you have added the correct identifier to your keychain sharing group. The default value is com.microsoft.adalcache.






    share|improve this answer



























      0














      You need to ensure you have added the correct identifier to your keychain sharing group. The default value is com.microsoft.adalcache.






      share|improve this answer

























        0












        0








        0







        You need to ensure you have added the correct identifier to your keychain sharing group. The default value is com.microsoft.adalcache.






        share|improve this answer













        You need to ensure you have added the correct identifier to your keychain sharing group. The default value is com.microsoft.adalcache.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 15 '18 at 1:16









        Paulw11Paulw11

        68.7k1086103




        68.7k1086103





























            draft saved

            draft discarded
















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53298417%2fmsal-failed-to-set-item-into-keychain-when-trying-to-authenticate-microsoft-gr%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            這個網誌中的熱門文章

            How to read a connectionString WITH PROVIDER in .NET Core?

            Node.js Script on GitHub Pages or Amazon S3

            Museum of Modern and Contemporary Art of Trento and Rovereto