Authenticating a Today Widget for API access - ios

I need to add a Today Widget/extension to an existing iOS app, which requires the user to sign in via a WKWebView.
As the extension only communicates with Apple frameworks or via openURL() back to the main app, how would I best share the authentication token stored in the main app with the Today Widget/extension, so that it can make authenticated API calls?
Can this be done with a shared keychain? Or is there another secure alternative?
It is not feasible to have the user sign in again in the Today extension UI.

You can use App Groups to share data between the main application and today widget extension. You need to activate App Group for your application and create:
UserDefaults.init(suiteName: "group.com.yourOrganization.yourApplicationName")
In the main application set your data in this UserDefaults and try to access it from within your Today Widget extension.

Use a Shared Keychain Group to store the token, as described at 14m00s in this WWDC video.

Related

Can I perform a task in Main iOS app from the app Extension?

I have an app extension for Sharing (Share Extension) and when a user selects my app to share an image, my app will send that image to a server.
The problem is that the server requires an authenticated identity (AWS Cognito) to send the object to the server. Since I cannot share Authentication from my main app to my extension and I don't want to have the user sign in every time they want to share, I'm stuck.
I can see this being done with messaging apps where a user sends a message from a share extension. I'm not sure how they achieve this. Since the user is not asked to login again in the extension, somehow the credentials are either being shared with the extension or the app is momentarily launched to perform that upload while remaining in the background (not sure this is possible).
So my question is what is the approach I should be using. Should the extension somehow be directing the main app to upload the image or should I figure a way of sharing the access tokens with the extension in a secure way and accessing them without any user action?
The solution is to setup a shared container for the app & the extension, please see "Sharing data with your containing app" section in this article: https://developer.apple.com/library/archive/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html#:~:text=To%20enable%20data%20sharing%2C%20use,App%20to%20an%20App%20Group.

How to share Parse login session with iOS extension?

When writing an iOS extension for an app, is it possible to share the app's current Parse login session with the iOS extension?
iOS extensions are bundled with iOS apps but run in separate containers. So when the user logged in on the app, the extension cannot access that Parse instance. If the extension logged in again, it would create an additional login session for the user.
However the extension can share a common data container with the app. So I wonder if it is possible to store the PFSession.sessionToken in the shared container and let the extension communicate with Parse Server based on that existing session without having to login?
There are two possible solutions:
A) The elegant approach
Enable local data sharing which shares persistent data between the main iOS app and its extensions.
// Enable data sharing in main app.
Parse.enableDataSharingWithApplicationGroupIdentifier("...")
// Enable data sharing in app extensions.
Parse.enableDataSharingWithApplicationGroupIdentifier("...", containingApplicaiton: "...")
Local data sharing in Parse SDKs allows you do share persistent local
data between your main application and extensions that it contains,
including Keyboard, Share/Today/Photo/Action extensions and Document
Providers.
As described in the docs.
B) The manual approach
After login in the app, store the Parse session token PFUser.current().sessionToken in an ecrypted, shared data container.
The extension can then access the session token and continue the session with PFUser.become(sessionToken:).

How to access current firebase user from iOS Today Extension?

We're building a today widget on top of our iOS app which is working with Firebase. However we're struggling to access current signed-in user from the extension. The user at the main app is anonymous so passing credentials via shared container is not an option.
The only way that I found is passing uid and generate custom token to sign in but I was hoping to find out better way to share FIRUser between my main app and app extension. What would be the best way to achieve this?
You can share data between Host App and App Extension only using App Group.
There is no way of direct communication between your Host App and App Extension.
Even though an app extension bundle is nested within its containing
app’s bundle, the running app extension and containing app have no
direct access to each other’s containers.
App Group is a shared container used by both Host App as well as App Extension. It is like UserDefaults that store key-value pairs.
So you can save your current user information in App Group from Host App and then access it in your Today Extension from the same App Group.
For more on App Groups refer to: https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html

How to use same Authenticated user token between main iOS app and its Share Extension

We have the main app integrated with Firebase SDK. User sign in via main application using email, google or facebook.
Now, we have share extension implemented which ideally should share same Authentication session internally so that data can be sent on Firebase with the same user without asking him to login again through the extension.
So, does anyone know the way to share Firebase authentication session between the Main app and share extension?
Either we sent some internal call to the main app to perform Firebase stuff because it has authentication detail within it.
The main app set some token to common user defaults via app groups which will be then used by Share extension to re-authenticate automatically.
Or Firebase provide some way to do so,
I don't know what is feasible from above.
I found a method signInWithCustomToken:completion: but, it's not related to what I actually looking for.
To read and save from the same set of NSUserDefaults you need to the the following:
In your main app, select your project in the project navigator.
Select your main app target and choose the capabilities tab.
Switch on App Groups (this will communicate with the developer portal, as it is generating a set of entitlements, and relevant App Id and so
forth).
Create a new container. According to the help, it must start
with “group.”, so give it a name like “group.myapp.test”.
Select
your Today Extension target and repeat this process of switching on
app groups. Don’t create a new one, rather select this newly created
group to signify that the Today Extension is a member of the group.
Write to your NSUserDefaults:
// In this example I´m setting FirstLaunch value to true
NSUserDefaults(suiteName: "group.myapp.test")!.setBool(true, forKey: "FirstLaunch")
Read from NSUserDefaults:
// Getting the value from FirstLaunch
let firstLaunch = NSUserDefaults(suiteName: "group.myapp.test")!.boolForKey("FirstLaunch")
if !firstLaunch {
...
}

Initiate Parent iOS App Service Call from Today Widget Extension

I am working on a POC iOS application that will eventually be released through an internal enterprise MDM solution. The app itself is pretty straightforward. It makes a quick call to an internal endpoint to return some simple json and then displays it on screen. At the same time, I have an app extension (Today Widget) displaying a small fraction of that data as well.
I have created a shared framework that includes the service calls, as well as any other common code I am using. Unfortunately, the parent app and extension all work perfectly fine if I'm on the internal network where the service endpoints live. However, this app will not always be on our trusted, internal network. As a result, we wrap the build with a secure container provided by our MDM solution and open up traffic to our specific internal endpoints. This works perfectly fine for the app, but our MDM provider doesn't currently provide similar capabilities for App Extensions.
As a result, I am working to come up with creative ways to best ensure the data in my Today Widget is up to date without it directly making a service call. To do so, I am sharing data between the app and extension via an app group, but if the service call is only made from the parent app and the user very rarely accesses the parent app, the data will still be out of date.
In order to simulate making the service call from the app extension to update the data, I would like a way to call the service on behalf of the parent app, which would then update the NSUserDefaults data being shared between app and extension.
So my question: What is the best way for me to initiate that service call in the parent app? Is it even possible? I know Apple provides the 'openURL' method to allow an extension to open it's parent app, but I don't want to actually open the app. I want the app to be running in the background while the extension makes the service call on it's behalf.
I have been looking into the following, but with not much luck:
Parent app has an observer on NSUserDefaults, watching a specific key, that when modified by the app extension will fire off the service call to update the shared data being displayed. Unfortunately, I don't believe this will work, since as long as the parent app is in the background, the NSUserDefaultsDidChangeNotification will not get fired off in the parent app.
Send a local notification from app extension to parent app, telling it to fire off the service call and update data shared via app group. Unfortunately, UIApplication.sharedApplication() is not accessible from an app extension.
Any suggestions of ways to simulate the service call, to give my Today Widget the highest likelihood of being up-to-date with it's information?
Note: Obviously giving Today Widgets access to internal resources has it's own security concerns, but for this POC, the data is non-sensitive and must only live internally..

Resources