How to trigger authentication in a File Provider Extension

Hi,


I'm implementing a File Provider Extension and I need to authenticate users before they can open files. My files are showing just fine in a Document Browser and can be opened. However I need the authentication.


From the WWDC 2017 video "File Provider Enhancements" at 48:45 I understand that the FPUIActionExtensionViewController function prepare(forError error: Error) is called when an authentication error happens (HTTP error 401 or ?). How can I test/trigger this?


If I try a "Custom Action" (from the Xcode template) the FPUIActionExtensionViewController function prepare(forAction actionIdentifier: String, itemIdentifiers: [NSFileProviderItemIdentifier]) is called just fine, and the custom view is presented.

I can't find any documentation on this.

Replies

Have you tried returning the error NSFileProviderErrorDomain + NSFileProviderError.notAuthenticated from startProvidingItem(at:completionHandler:)?


let error = NSError(domain: NSFileProviderErrorDomain, code: NSFileProviderError.notAuthenticated.rawValue, userInfo:[:])
completionHandler?(error)


https://developer.apple.com/documentation/fileproviderui/fpuiactionextensionviewcontroller/2919962-preparementions this in its discussion.

Hi @benqwerty,


Thank you!


I have tried what you suggest, i.e. returning the notAuthenticated error to the completionHandler in startProvidingItem(at:completionHandler:), but I just get a "The operation couldn't be completed. (com.apple.FileProvider error -1000.))" alert box with the only option to choose "OK". (See https://developer.apple.com/documentation/fileprovider/nsfileprovidererror.code/2887598-notauthenticated)


I was thinking that this might have something with App Groups to do. I.e. I tried to add both my file provider extension and the file provider extension UI (containing the FPUIActionExtensionViewController) to the same App Group, but this did not change anything.


Do you have a working solution?

Hi,


I have created a test project to show the problem, it can be found af https://github.com/sejersbol/TestAuth


This tests the authentication for files requiested via a File Provider Extension. Enclosing app for the file provider extension is a Document Based App. The test app is build using the templates for the Document Based App and File Provider Extension from Xcode 11.


In https://github.com/sejersbol/TestAuth/blob/070be6b7543fde0b0604cc77cadc8a6c67923b55/TestAuthFPE/FileProviderExtension.swift#L95 I try to trigger the authentication, but it is not working.


Anyone?

It's work in progress. I have not yet got my exension working exactly as I want it but I have managed to get an authentication prompt now. It seems you need to throw the error from enumerator(for:). Try this. It gives me a system "authentication failed" view with an Authenticate link, then my FileProviderUI gets called when I tap that.


    override func enumerator(for containerItemIdentifier: NSFileProviderItemIdentifier) throws -> NSFileProviderEnumerator
    {
        let simulateServerAuthFailure = true

        let maybeEnumerator: NSFileProviderEnumerator?
        if (containerItemIdentifier == NSFileProviderItemIdentifier.rootContainer)
        {
            if simulateServerAuthFailure {
                // Simulate an authentication error
                let error = NSError(domain: NSFileProviderErrorDomain,
                                    code: NSFileProviderError.notAuthenticated.rawValue,
                                    userInfo: nil)
                throw error
            }
            else {
                // Create real enumerator
                ...
            }
       }  
       ...

        return enumerator
    }

Hi @benqwerty


Yes! That worked! I have updated my example file provider extension on GitHub to reflect this solution. In the simple test app I just communicate that the user is authenticated from the file provider extension UI to the file provider extension using UserDefults and a shared App Group. There might be a better way (?).


Now, my next big question is, how do we logout an already authenticated user? Any ideas? I was thinking of maybe calling a custom action on the file provider extension, but it is kind of silly that you should have to longpress on a file (in a document based app) and then choose logout.

Good news. Yes, I think communicating the account credentials between your FileProviderUI and the FileProvider using shared data (whether UserDefaults or a group container file/database) is the right way.


As for logout, do you mean a user-initiated manual logout, or handling an "account session expired" auto-logout that requires the user to re-authenticate? User-initiated manual logout: Presumably your app that bundles the FileProvider extension has some UI, so maybe that's the place for it. Session expiry: if you detect this somehow then I suppose you just call NSFileProviderManager.signalEnumerator on the root container then it will call your enumerator again and you can throw your authentication error. (That's theoretical; I haven't tried it.)

By the way I've just noticed that Xcode 9.2 beta has updated the FileProvider template code and fixed some errors:

func item(for identifier: NSFileProviderItemIdentifier) throws -> NSFileProviderItem?

is corrected to:

override func item(for identifier: NSFileProviderItemIdentifier) throws -> NSFileProviderItem


and a providePlaceholder(at:completionHandler:) override is now provided.

Thanks!


I'm thinking of an manual logout, and I agree that using the app UI of the File Provider Extensions enclosing app would be doable. However, I don't think it is a really nice solution. Also, we are planning on running the app that uses the File Provider Extension in Single App Mode, thus it will not be possible to change to the File Provider Extensions enclosing app for logout (I might be wrong on this... anybody?).


Your solution for "session expired" sounds reasonable to me.

Yes, I noticed the problem in Xcode 9.1 after it had been bugging me for about 30 min. :-) (see https://github.com/sejersbol/TestAuth/blob/fec2435a6b2b101ad8ba8e7778472f870bfbc9c6/TestAuthFPE/FileProviderExtension.swift#L24)