Blog Header@2x

Certificates, Provisioning Profiles, and Expiration Dates: The Perfect Storm

As you may have read, this weekend was a little hectic for us and some of our app developer friends1. On Saturday we got word that users of 1Password for Mac were seeing the app fail to launch correctly. It took a few hours, but we diagnosed the problem and released an update that corrected the issue. This issue will only have affected users that downloaded 1Password for Mac directly from our website, so if you downloaded it from the Mac App Store you had a much more calm weekend than we did.

But alas, that story has already been told. Now it’s time for the nitty gritty technical details about all the forces that aligned against us that had us staring up a giant wall of crashing water like George Clooney and Mark Wahlberg.

Prologue: Not All Certificates Are Created Equal

There’s a lot of information to unpack in this post, but before I get started, I’d like to address an assumption I’m seeing far too many people making: that what happened to us was simply an issue of an expired certificate and that all we needed to do was create a new one, just like you do for SSL certificates.

That’s simply not true.

Developer certificates are much different than SSL certificates and serve a very different purpose. Unlike a simple SSL certificate, our developer certificate is used to sign 1Password and needs to be valid during build time. The expiry time of a certificate or provisioning profile should have no impact on whether or not macOS will allow an app to launch or not.
An analogy may be helpful here: if you think of the developer certificate as a carton of eggs, and 1Password as a cake, then it is important not to use expired eggs to make the cake. The fact that the eggs may expire a few days after making the cake should have no effect on the cake itself. After all, the cake is already made and delivered.

Jumping out of the galley and back into our developer world, an expired certificate typically doesn’t affect us until the next time we need to do a release, which would have been this week with our next betas. Certificates control our ability to sign new apps. They don’t affect existing released apps.

For example, we have some users still using 1Password 3 for Mac (hey there, if that’s you, you should really consider upgrading to a 1Password membership as soon as possible!). The first release of 1Password 3 was in 2009, around 8 years ago. Assuming a user is happy with 1Password 3, how long should they expect to be able to continue using the software they paid for? The only acceptable answer to that question is: as long as they feel like it.

Obviously there’s plenty of reasons for why a user would want to upgrade to newer versions, but the fact of the matter is that a user shouldn’t be reliant on us to keep providing updated builds of an unmaintained app just to keep it running. Unlike an SSL certificate, this isn’t something we can simply fix from our end. Fixing the issue we ran into this weekend is a matter of creating a new build of the app and having users update to the new version.

Taking a Tour of the Engine Room

iCloud Sync

To properly understand what happened, let’s take a step back and look at the different parts of this.

In Mac OS X 10.7 Apple introduced Gatekeeper. Gatekeeper is really quite awesome as it gives users control over what software is allowed to run on their system. The default is to allow software from verified and trusted developers: those apps that have been uploaded to the Mac App Store, or those signed with Developer ID certificates made available to the developer by Apple.

Gatekeeper ensures that apps that have been tampered with will refuse to run, and also provides Apple with a way to revoke certain certificates if a developer has been found to be doing harm (i.e. distributing Developer ID signed malware). These simple steps stop a wide variety of attack vectors and we think the world of Apple for having implemented this.

The next layer is the Provisioning Profile. Provisioning Profiles provide information about what the app can do, as well as who can run it. There are certain services on the Mac that require that the app include a Provisioning Profile. In our case, we needed to start using a Provisioning Profile when we added support for unlocking 1Password using Touch ID.

To be clear, Touch ID itself doesn’t necessitate the profile, but in order to unlock your vault we need to store a secret and we choose to store it the OS X keychain. The specific configuration we’re using for that requires declaring that we want access to a specific keychain access group, which needs to be declared in a provisioning profile. The provisioning profile is included in the app bundle and cannot be updated independently of the app.

Next up… XPC. We use XPC to communicate between the 1Password main app and 1Password mini – the little 1Password that runs in your menu bar – and it’s really quite awesome. 1Password mini acts as the brains of the whole operation, and the larger app is mostly just responsible for displaying information. The reason we love XPC so much is because it’s an inter process communication tool that actually provides us the building blocks we need to perform mutual authentication. What this means is that 1Password mini will refuse to communicate with the main app unless it can prove that it’s signed by us. The inverse is true as well.

Storm Clouds Gather

clouds-gathering@2xAt around 3pm EST on February 18th we started getting reports of failures in 1Password for Mac. Folks were seeing an error appear that 1Password was unable to connect to 1Password mini.

Unable to start 1Password

This initial failure occurred due to the fact that the provisioning profile embedded in 1Password mini had an expiration date. Expiration dates seem to be required, and due to the fact that the expiration date elapsed, Gatekeeper decided that 1Password mini was no longer safe to run. We’ve filed a bug with Apple as we feel that this shouldn’t be the case (rdar://30631968 for those of you reading along inside the Mothership).

Only 1Password mini contains the Provisioning Profile as all Touch ID operations happen within that process. This meant that Gatekeeper was deciding that our main 1Password app could launch. Upon launching, 1Password performs its start up sequence which includes asking the system to launch 1Password mini if it’s not already running. When doing so, the system would log the following to the console:

com.apple.xpc.launchd[1] (2BUA8C4S2C.com.agilebits.onepassword4-helper[11038]): Binary is improperly signed.
com.apple.xpc.launchd[1] (2BUA8C4S2C.com.agilebits.onepassword4-helper[11038]): removing service since it exited with consistent failure reason When validating /Applications/1Password 6.app/Contents/Library/LoginItems/2BUA8C4S2C.com.agilebits.onepassword4-helper.app/Contents/MacOS/2BUA8C4S2C.com.agilebits.onepassword4-helper:
Code has restricted entitlements, but the validation of its code signature failed.
Unsatisfied Entitlements:
com.apple.xpc.launchd[1] (com.apple.ReportCrash[11041]): Endpoint has been activated through legacy launch(3) APIs. Please switch to XPC or bootstrap_check_in(): com.apple.ReportCrash

The 1Password main app detected the failure and provided an error panel telling the user that it couldn’t connect to mini.

Due to the expired Provisioning Profile, 1Password mini wouldn’t launch. And without mini running, 1Password itself was unable to startup successfully. Both mini and 1Password itself were signed with the same Developer ID certificate. Gatekeeper allowed 1Password to run, but due to the different rules for apps with provisioning profiles, it would not allow mini to run.

As far as we can tell, the only way to correct this problem is to provide a new build of the app with an updated provisioning profile with a new expiration date. Within a few hours we were able to publish a new version which did exactly this. As of 6.5.4, we had an app that users could download and run again.

The Eye Of The Storm

eye-of-the-storm@2xAfter this initial bout of terror, death defying feats, and mad scrambles we figured the technical portion of this exercise was finished and had begun transitioning into customer support mode; helping allay the fear, uncertainty, and doubt that this event had caused.

Little did we know at the time, we were only in the eye of the storm – the calm center before things would get rough again.

1Password for Mac includes an updater within the app so that users can easily upgrade to the latest versions as they become available. This updater validates downloads before performing the update to ensure that the updated app is in fact from AgileBits. One of the steps taken during validation is looking at the code signature of the downloaded app and ensuring that it satisfies the following security requirement:

anchor apple generic and identifier com.agilebits.onepassword4 and certificate leaf[subject.CN] = “Developer ID Application: Agilebits Inc.”

This check has worked really well for us. It’s simple and does the trick.

This check is also extremely specific about the common name2 it looks for. When we generated our updated provisioning profile we also needed to generate a new Developer ID certificate. We didn’t realize it at the time, but the common name of newly created certificates now include the team identifier in addition to the company name;  “Developer ID Application: AgileBits Inc. (2BUA8C4S2C)” vs. “Developer ID Application: AgileBits Inc.”. Close. Super close. But we weren’t looking for a “close” match.

The result of this new common name was that even though our app would now launch, the automatic updater would never run successfully because as far as it was concerned the update being provided wasn’t valid and therefore needed to be rejected. This is what users who could still run 6.5.3 and tried to update to 6.5.4 saw.

Once we discovered this problem we had no choice but to pull the 6.5.4 update and issue a 6.5.5 update that included a modified security requirement check. Sadly this didn’t address the fact that users running 6.5.3 and earlier are not able to automatically update to 6.5.5.

Moving Forward and Heading Home

heading-home@2xThis was painful for everyone. We lost sleep over the weekend, but worse than that… our users temporarily lost access to some of their most important information. This is unacceptable to us and we want to make sure this doesn’t happen again.

We’ve reached out to Apple for help and guidance on what we can do to avoid this happening again in the future. Our new provisioning profile doesn’t expire until 2022, but we’ll make sure that this is resolved far before then so that you need not worry about that happening.

If you’re a developer of a Developer ID signed app, we recommend that you check to see if your app includes a provisioning profile. Since that’s mostly handled automatically by Xcode, it’s likely that there are apps out there whose developers aren’t even aware of the inclusion of the provisioning profile. Check the expiration date, and ensure that you release an updated build with an updated provisioning profile well before the expiration date is hit so your users have time to update.

We’ve also filed an enhancement request with Apple asking that developers be notified via email of impending distribution certificate or provisioning profile expirations with explanations of repercussions. This was filed as rdar://30631939.

If you have questions about any of this, please don’t hesitate to ask us in the comments below.

Love,
The 1Password Mac Team
❤️

P.S. Happy 5th Birthday to Gatekeeper! 🎂 We were one of the first apps to sign with Developer ID certificates, use XPC, and leverage the entitlements required for Touch ID. It’s always exciting being on the cutting edge of technology but we wouldn’t have it any other way. 🙂


  1. The exact same perfect storm appears to caused our friends at Smile to hit the same rough seas that we had. You can see Adam Engst’s story in TidBITS for details on how this affected PDFPen. 
  2. The Common Name is the subject.CN part of the security requirement. As our Chief Defender of the Dark Arts often says of Common Names: they are often very uncommon. The name is inherited from older identify management systems. I don’t need to say much more as Jeff loves explaining things, so let’s all sit back and watch what he says in his comment that I’m sure he’ll be adding soon. 
agconf-7

Having a blast at AGConf[7]

Every year since I joined the AgileBits family, I’ve looked forward to our annual reunion. It’s a rare opportunity to see the faces and hear the voices that only exist in my head and in text most of the time. AGConf gives us the chance to get together, discuss, plan, collaborate, joke, sing, dance, and occupy the same space for one glorious week.

Suffice it to say that AGConf[7] was a blast. We all met in Fort Lauderdale, Florida, where we boarded the Independence of the Seas for a five day Caribbean cruise. We visited Labadee, Haiti, and Falmouth, Jamaica, before making the return trip and parting ways.

Seeing the same old friendly faces

Most of us work remotely, and with the exception of the odd trip to the mothership (Toronto), we don’t get to see each other. The first day is filled with hellos and hugs–and an abundance of both. We always keep our eyes out for the official AGConf tees, and this year’s 007 themed one was a big hit!

Seeing the shiny new faces

In addition to seeing our old friends and colleagues, it’s always fun to meet the new Bits on the team! It seems like we’re growing exponentially these days, and by some wonderful Agilemagic, everyone fits in just right. I’m already looking forward to meeting more new Bits next year!

Getting some work done

Getting such great minds together always makes for some interesting discussion. It’s fun to put our heads together to help customers, solve problems, and make plans for the future. It’s also one of the few times during the year where we can have face to face discussions. Any big plans we’ve been working on in secret can finally be revealed. Any questions we’ve been wanting to ask get answered, sometimes with a full lecture.

Beyond all of the enlightening and productive internal discussion, we also spend a lot of time supporting our customers. At AgileBits, we take customer support very seriously, and everyone takes part in it. On the high seas, we all have each other to bounce ideas off of, or help with tricky issues we may not be too sure about. Need a developer? Just grab one. Have a security question? Goldberg’s got you covered. Working during AGConf almost doesn’t feel like work at all.

Having lots of fun

And of course, when we get together, we have fun. We play games, soak in the hot tubs, drink Labadoozies and rum punches galore, get dressed up fancy for dinner, sing karaoke, eat lots of dessert, get late night pizza, do yoga, watch the sun rise and set…I could go on. There’s so much to do, and so many people to see, it’s hard to make sure to get enough sleep! For a bunch of computer geeks, we’re a pretty rad crew.

 

Parting is such sweet sorrow

Like all other good things, AGConf, too, must come to an end. We came, we saw, we conquered, and we did some other stuff too. Now it’s time to get back to developing software we’re passionate about, and supporting customers we love. Until next time, Bits!

DevBits header

AgileBits Presents: AgileCloudSDK

Today we’re pleased to announce that AgileCloudSDK is officially open source and available on GitHub. AgileCloudSDK is a framework that we’ve built for the purpose of bringing iCloud sync to the AgileBits Store version of 1Password. AgileCloudSDK allows us to take our existing iCloud sync solution and make it work outside the Mac App Store.

Get the Code

Enough with the pleasantries, let’s get to it! All of the code is up on GitHub. The repository includes the framework, two sample apps (one using CloudKit, the other using AgileCloudSDK), and instructions on how to get set up.

Compatibility

Using both CloudKit JS and CloudKit REST Services, AgileCloudSDK is a drop-in replacement for the official CloudKit framework. Its core functionality is compatible enough that for our sync code, the only difference between it and CloudKit is which framework header we import. The gap is a little wider for sync setup, because OS X and iOS handle all the authentication automatically when using CloudKit.

When using CloudKit JS or the REST Services, authentication is not handled automatically. In this case, AgileCloudSDK brings the user to the CloudKit authentication page in their browser. After a successful login, an authentication token is returned to the app.

AgileCloudSDK auth

The differences in authentication required us to modify how sync is configured in 1Password, but thankfully the changes we had to make were fairly minimal.

One of the many benefits of using AgileCloudSDK is that developers can target either the development or production CloudKit container, which is invaluable for debugging issues in a production environment.

Getting Here

The first stage of AgileCloudSDK development was to simply build this thing for our own purposes. It was important to us that we explain to our users how we managed to get iCloud sync outside the Mac App Store; announcing the framework a few months ago was our way of doing that.

The next phase was to get more real-world experience with the framework and to fix issues as they came up. We’ve been refining AgileCloudSDK and we’re really happy with how it’s working out so far, and we think it’s ready for others to use it.

Going Forward

We’re now entering the third phase of AgileCloudSDK development. This is where we would love all you app developers to get involved. AgileCloudSDK contains implementations of every CloudKit class that 1Password uses, which is the majority of them. See our GitHub project page for a list of classes that are not implemented. We’d love for AgileCloudSDK to implement 100% of the CloudKit API.

We used both CloudKit JS and CloudKit REST Services to implement AgileCloudSDK. CloudKit JS is almost always the quickest way to get something built, but the REST services allow more flexibility. We’d love to see more code converted to using only the REST services, with the goal of one day breaking the dependence on any main-thread processing.

Feedback

For general feedback, leave a comment below or e-mail us at support+agilecloudsdk@agilebits.com. If you have questions or comments on implementation, or if you find a bug, please file an issue in the repo.

DevBits header

AgileCloudSDK: iCloud Sync Gets Its Wings

At the last WWDC, Apple announced some changes to CloudKit, the technology that enables an app to sync with iCloud. As many of you know, it was previously impossible for non-Mac App Store apps to sync with iCloud. The changes that Apple made to CloudKit have opened up some really exciting possibilities, and today, we’re happy to announce that we have been able to implement iCloud sync in the AgileBits Store version of 1Password.

1Password 6 for Mac Sync Preferences (iCloud)

Wait…what?

1Password uses the CloudKit API to sync your data with iCloud. In OS X 10.10 Yosemite, the CloudKit framework provided by Apple did all the heavy lifting by communicating with Apple’s servers for the app, but it was only available for apps that were codesigned by the Mac App Store. This meant that only the Mac App Store version of 1Password could sync with iCloud.

You can read more about this in the post that Roustem wrote last fall.

What’s changed?

CloudKit is still the way that developers access the iCloud database, but Apple has provided a brand new way of accessing their CloudKit servers: CloudKit web services. CloudKit web services allows apps to access CloudKit via a really nice web framework called CloudKit JS. When these changes were announced at WWDC, we were excited to start working with this new framework to see what possibilities it would present. Ultimately, CloudKit JS enabled us to support iCloud sync in our AgileBits Store version of 1Password.

[Update] If you are a Mac app developer, and would like to use AgileCloudSDK so that your app can sync with iCloud, your app must also be in the App Store. Your customers, however, will now be able to choose whichever version they want.

How did we do it?

To make sync as seamless and stable as possible we wanted to make very few changes to the existing sync code in 1Password. We felt the best way to do that was to make a framework that looks and acts like Apple’s native CloudKit framework, but uses the CloudKit web services. This means 1Password can use Apple’s native CloudKit framework in the Mac App Store version, and our new AgileCloudSDK framework in the AgileBits Store version.

There are a lot of internal differences between native CloudKit and CloudKit web services. CloudKit web services relies on JavaScript but native CloudKit uses Cocoa classes for data storage, so we knew that we couldn’t reuse the existing code without something to translate the requests and data back and forth.

In order to talk to Apple’s servers, we needed a mediator. Adam Wulf and I created a class that takes native CloudKit API calls, translates them to web service API calls, and translates the responses back to native Cocoa code. The 1Password sync code is now completely ignorant as to whether it’s connecting to native CloudKit or CloudKit web services. This means that 1Password can find your data in iCloud, whether you’re using the Mac App Store version or the AgileBits Store version. We’re extremely pleased with this outcome!

From our customers’ point of view, iCloud sync in the AgileBits Store version of 1Password will look a little bit different during the initial setup. CloudKit JS does not use the iCloud settings from OS X, so to authenticate with Apple, 1Password will prompt you to log in to your iCloud account by displaying the iCloud login page in your default web browser. Once you have logged in to your iCloud account, CloudKit web services sends an authentication token back to 1Password, which it then stores (securely, of course). This enables 1Password to sync with iCloud without having to reauthenticate each time. Since the iCloud login for CloudKit JS is completely separate from the iCloud settings in OS X System Preferences, you can even use a completely different iCloud account if you like!

1Password 6 for Mac iCloud auth

Share the knowledge

One of the challenges we faced when developing this framework was that no one else seemed to be working on this particular problem yet. We want AgileCloudSDK to continue to grow and improve and we can think of no better way to ensure that than to release it as open source. We are currently busy prepping it for release and plan to have more information (including a release date) soon. If you’re interested in learning more about this framework, reach out to us at support+agilecloudsdk@agilebits.com.

To everyone at Apple who worked hard to make this new functionality possible: thank you. You’re awesome.

1Password for iOS header

iOS 9.2 adds 1Password to many new apps

During WWDC this year, Apple announced SFSafariViewController. This was really exciting news for us. Just imagine: if a third-party app used Safari as its in-app browser, that would mean that 1Password could fill Logins automatically without developers doing any extra work!

SFSafariViewController was introduced to everyone in iOS 9. Immediately, we began receiving reports from customers about 1Password disappearing from their favourite apps! It turns out that the JavaScript we were using couldn’t be executed in SFSafariViewController. We did some work on our end to address this issue and also reported it to Apple. Then, we waited.

Patience is a virtue

A Very Rad Holiday

One day in late October, while I was on vacation in a place where Internet access was scarce, Slack exploded with mentions from my colleagues about 1Password automatically working in many new apps when using the new iOS 9.2 beta. There I was, with an Internet connection barely good enough to check my email, and with no way to download the new iOS and Xcode beta goodies. All I could do was wait. And wait. And wait. It was the first time I ever wished that my vacation would end sooner!

Yay! Thank you, Apple!

Finally I returned home and was able to verify the amazing news: the 1Password App Extension API will simply appear in all Safari View Controllers in any app! After spending weeks working on this, I was ready to buy everyone at Apple a beer.

Let’s have a look at how this actually works. In the following example, you can see how easy it is to use 1Password to add your account to Tweetbot, one of the most popular Twitter clients.

What’s even more awesome is that Paul (the developer of Tweetbot) didn’t need to do anything to enable this feature. It just works! If you are an app developer, users of your app simply have to make sure that the 1Password App Extension is enabled.

To enable 1Password in apps, simply set up 1Password. It will then appear as an option on the share sheet, where it can be toggled on and rearranged. For illustrated, step-by-step instructions, please see our user guide.

1Password ❤ App Developers

The 1Password App Extension offers iOS app developers the opportunity to provide a simple and secure login experience. If your favourite iOS app prompts you to log in and doesn’t display the 1Password icon, reach out to the developer and direct them to our Dev Outreach page. They’ll be amazed by how easy it is to integrate 1Password into their app.

If you’re a developer and have already added the 1Password app extension to your iOS app, thank you; you’re awesome! Please don’t forget to submit your app to our Apps ❤ 1Password directory.

1Password developer newsletter

iOS app developers are invited to subscribe to our 1Password App Extension Developers newsletter. We’ll send you an occasional newsletter containing 1Password App Extension news, updates, and tricks, to help you realize the full potential of the 1Password Extension API in your iOS apps.

If you have any questions, you can comment on our GitHub project or email support+appex@agilebits.com. I look forward to talking to you!

DevBits header

1Password App Extension API and time-based, one-time passwords

The App Extension API was released as a companion to 1Password 5 for iOS last year. Now that 1Password 6 is out, I’m sure some of you are curious to learn about what’s new in the API. To celebrate the App Extension API’s first anniversary, I’d like to tell you about one of its best-kept secrets: Time-based, One-time Passwords (TOTPs).

TOTP + 1Password extension = 🔐

Did you know that our App Extension API supports one-time passwords? In fact, it’s been there since version 1.5 of the API. If you haven’t already, I recommend that you upgrade to the latest version, 1.6.1. Not only can your users fill their usernames and passwords in your app with a few simple taps, their one-time passwords can be filled just as easily.

Best of all, it’s an absolute cinch to implement: simply check whether the one-time password exists in the login dictionary from findLoginsForURLString:

@IBAction func findLoginFrom1Password(sender:AnyObject) -> Void {
        OnePasswordExtension.sharedExtension().findLoginForURLString("https://www.acme.com", forViewController: self, sender: sender, completion: { (loginDictionary, error) -> Void in
            
            // Fill the username and password into the fields
            self.usernameTextField.text = loginDictionary?[AppExtensionUsernameKey] as? String
            self.passwordTextField.text = loginDictionary?[AppExtensionPasswordKey] as? String

            // Check if the user has a One-Time Password for the selected 1Password Login
            if let generatedOneTimePassword = loginDictionary?[AppExtensionTOTPKey] as? String {
                self.oneTimePasswordTextField.text = generatedOneTimePassword

                // Important: It is recommended that you submit the TOTP to your validation server as soon as you receive it, otherwise it may expire.
                self.submitRightNow()
            }
        })
    }

That’s all it takes to make your users’ lives much simpler.

1Password ❤ App Developers

If you have already added the 1Password app extension to your iOS app, thank you; you’re awesome! This new functionality gives you the ability to make security even more convenient for your users, and I can’t wait to see how you use it. Please don’t forget to submit your app to our Apps ❤ 1Password directory.

A newsletter just for you

You can also subscribe to our 1Password App Extension Developers newsletter. We’ll send you an occasional newsletter containing 1Password App Extension news, updates, and tricks, to help you realize the full potential of the 1Password Extension API in your iOS apps.

If you have any questions, you can comment on our GitHub project or email support+appex@agilebits.com. I look forward to talking to you!

DevBits header

Web View Filling ups the awesome factor of the 1Password App Extension

App Developers, this one’s for you!

Since the introduction of the 1Password App Extension API, support for the extension has been added to over 200 apps. We are so excited by this show of support from the development community that we decided to add functionality to the App Extension API to make it even more useful for you and more powerful for your users.

Version 1.5 = (Web View Filling)^2

As most of you already know, the 1Password Extension was originally designed to fill login details (usernames and passwords) in Safari and third-party applications. Thus far, the primary use of 1Password in third-party apps has been to sign in, which means that users likely invoke 1Password only once, right after installing your app.

In the latest update, we’ve made the app extension more powerful and more versatile. I am happy to introduce you to the redesigned Web View Filling capability of the 1Password App Extension API, which will enable your users to use 1Password to fill not only Logins, but also Credit Cards and Identities in any of your app’s web views.

From a technical point of view, this updated capability works in a similar fashion to the original Web View Filling: it can fill 1Password items in web views. However, to get the best user experience from the 1Password Extension, we should treat it as two distinct capabilities. Let’s take a quick look at what makes these two options unique, so that you can determine the best choice for your use case.

Scenario 1: Authentication

Let’s say users have to sign in to a service before they can use your app. When the user opens your app, they are presented with a web view in which they can enter their username and password to log in. In this case, you do not want the user to be distracted or confused by Credit Card and Identity items. You only want the Login for the service to show up in the 1Password Extension so the user can log in quickly.

Login selection screen using app extension API 1.5

Scenario 2: Web Browsing

  • Can your users purchase items from your web store?
  • Can your users sign up for a service by entering their information in to a web view?
  • Does your app have a built-in browser?
  • Does your app have billing and/or shipping forms for users to fill?
  • Would you like the 1Password Extension to show in the share sheet?

If you answered “yes” to at least one of the above questions, consider adding support for 1Password using the wonderful new Web View Filling capability, which will enable you to permit the filling of Credit Cards and Identities. You will also benefit from the fantastic new Brain filling logic we use in 1Browser and Safari.

This capability will help make your users’ browsing experience simple and secure by filling Login details, Credit Card items and Identities.

Fill Login, Credit Card, and Identity info when using app extension API 1.5

The Code

Choosing between the two scenarios is very easy: simply decide whether you want to show the Credit Cards and Identities that the user has stored in 1Password. To show only 1Password Login items in the 1Password app extension, pass YES as the parameter for showOnlyLogins. To unlock the full awesomeness of the 1Password app extension and take advantage of the new Web View Filling of Logins, Credit Cards and Identities, pass NO. That’s really all there is to it!

- (IBAction)fillUsing1Password:(id)sender {
    [[OnePasswordExtension sharedExtension] fillItemIntoWebView:self.webView forViewController:self sender:sender showOnlyLogins:NO completion:^(BOOL success, NSError *error) {
        if (!success) {
            NSLog(@"Failed to fill into webview: <%@>", error);
        }
    }];
}

1Password ❤ App Developers

I want to take this opportunity to thank all of you app developers who have already added the 1Password app extension to your apps; you’re awesome! This new functionality gives you the chance to make security even more convenient for your users, and I can’t wait to see how you use it. Please don’t forget to submit your app to our Apps ❤ 1Password directory.

A newsletter just for you

You can also subscribe to our 1Password App Extension Developers newsletter. We’ll send you an occasional newsletter containing 1Password App Extension news, updates, and tricks, to help you realize the full potential of the 1Password Extension API in your iOS apps.

If you have any questions, you can comment on our GitHub project or email support+appex@agilebits.com. I look forward to talking to you!

DevBits header

Improved locking in 1Password 5.5 for iOS

Security and convenience

One of the coolest features in 1Password for iOS is the extension. For nearly a year, it’s been really easy to log in to participating apps without having to copy and paste usernames and passwords. Shopping in Safari is also a breeze, now that you can add items to your cart, then fill in your credit card and address with just a couple of taps. The icing on this cake is that you can log in to 1Password using Touch ID instead of tapping out a PIN or your entire Master Password over and over again.

Integral to the extension is the 1Password Lock Service, which determines how often you’re prompted to unlock the app and whether you’re prompted to use quick unlock (Touch ID or PIN Code) or your full Master Password. Thanks to the feedback you’ve provided, the Lock Service has gone through a couple of transformations since iOS 8 was released last fall. The latest update to 1Password is no exception and includes some major improvements that we’re sure you’ll love!

Touch ID: The star of the show

When Apple announced Touch ID on the iPhone 5s in 2013, we knew it would be the perfect way to unlock 1Password for iOS quickly and securely. It took a year before we were able to integrate it, but it was definitely worth the wait!

1Password for iOS Touch ID lock screen

In previous versions of 1Password, cancelling the Touch ID prompt cleared your Master Password from the iOS Keychain, which meant that you would have to enter your Master Password before you could use Touch ID again. This was inconvenient, especially when your goal was just to dismiss the Touch ID prompt without unlocking 1Password.

In version 5.1, we decided to force quit the main app and dismiss the extension when the Touch ID prompt was canceled. It seemed like a good idea, but it was confusing because it looked like the app was crashing. So we went back to the drawing board.

In 1Password 5.5, canceling Touch ID will cause 1Password to display the Master Password prompt, but your password won’t be cleared from the iOS Keychain. This means that you will be able to use Touch ID the next time you open 1Password without typing your Master Password; all you need to do is to tap the fingerprint icon to bring up the prompt.

1Password 5.5 for iOS Master Password lock screen with Touch ID icon

Lock Service: Centralized and better than ever

In 1Password 5.5 for iOS, we have created a “central” Lock Service that is shared between 1Password and its extension. The extension will now use the settings you have specified in the main app. Additionally, when you unlock the 1Password extension, you will also unlock the main app (and vice versa). Those of you who use 1Password on Mac will probably notice that this is similar to the way 1Password and 1Password mini lock and unlock in unison.

As long as you have Lock on Exit disabled, you will no longer be prompted to unlock 1Password moments after you unlock the extension in Safari. Depending upon your Auto-Lock settings, it may be as long as an hour before you’re prompted to unlock 1Password again.

1Password 5 for iOS security settings

iOS Keychain + 1Password Extension = ❤️

In previous versions of 1Password, the extension never saved the Master Password to the iOS keychain. This meant that if your Master Password were cleared from the iOS keychain (like when you restart your iPhone or iPad), you would have to launch the main 1Password app and enter your Master Password before you’d be able to use quick unlock. Entering your Master Password in the extension would allow you to access your vault, but you’d have to keep reentering your Master Password until you finally unlocked the main 1Password app.

Now it doesn’t matter if your Master Password is cleared from the iOS keychain! If you have quick unlock enabled, you’ll just need to enter your Master Password in either the extension or main app—once. After that, you’ll be able to use quick unlock until the next time your Master Password is wiped from the keychain.

It’s taken some time and experimentation to get the main 1Password app and the extension working together just so, but we think our latest changes offer a balance of security and convenience. We hope you’re as happy with this update as we are! We’d love to hear your thoughts in the comments and in our discussion forums.

DevBits header

Accessibility in 1Password for iOS

At AgileBits we believe that everyone should be secure online. That means we want 1Password to be usable by as many people as possible. We have worked hard to implement many features that make 1Password more accessible. In this post I will explain some of the technologies we’ve taken advantage of to improve accessibility in 1Password for iOS.

What We Have Done

While our efforts are ongoing, here are some of the areas in 1Password where we offer accessibility features.

Colour Vision Deficiency and Password Readability

You may have noticed that when viewing a password, 1Password colours numbers and symbols differently. This is not only for convenience. We have carefully chosen colours easily seen by those who have trouble distinguishing different shades of a colour. We have tested for deficiencies related to protan, deutan, and tritan.

Those with achromatopsia (no ability to distinguish colour) must rely on character shapes to tell them apart. 1Password therefore offers a choice of fonts to make it easy to distinguish between the letter o and the number zero; and between lowercase l, capital I, and the number one.

colouredpasswordcropped

Large Type

Sometimes you have to enter a password on another device that cannot run 1Password (e.g. a combination lock, employer’s computer, etc.). For this reason, we provide the large type feature that, when activated, displays the password as large as possible for easy reading when entering it elsewhere.

largetype

Dynamic Type

iOS provides a great feature called dynamic type. This allows apps to dynamically adjust the size of text to user settings. You can experiment with dynamic type in the iOS Settings app in General > Accessibility > Larger Text.

As a developer, it’d be too easy just to turn the feature on and leave it at that. But that would result in text that grows too large for the screen and ends up getting truncated to the point that it is unreadable, or it would push interface elements so far out of the way that they are unusable. Less important text could also crowd out more important text.

We’ve taken care to limit text size where necessary and ensure inevitable truncation happens such that the most important part of the text is still shown. We’re even looking at ways to rework the UI when the text is too large to fit.

dynamictype

VoiceOver

Apple has a fantastically comprehensive voice-over system in iOS. In 1Password we take advantage of that by ensuring all of our interface elements and data values are properly labeled for accessibility so VoiceOver can read them aloud in a context that makes the app more usable. We have also minimized redundancies in describing the interface to make sure relevant interface elements are described quickly and effectively. To keep your passwords secure, 1Password will not read your passwords aloud unless you explicitly request it.

Work in Progress

As interfaces in software change and new features get added, accessibility support can change too. If there’s an accessibility feature you would like to have, or something you feel is not implemented as well as it could be, please let us know! We welcome feedback and want to make 1Password more usable for all of our awesome users!

DevBits header

The endless waltz: making custom UI for Windows Modern

Branding is a promise. It’s a guarantee of what to expect and a derivation of an identity. Here at AgileBits, we have strong brand identity and our customers can immediately recognize our app, no matter the platform on which they see it. As a recent addition to the AgileBits family, working on the latest addition to the 1Password application family, one of my priorities has been to ensure our new app feels like 1Password. But this, like so many other things, is easier said than done.

At first blush (and second, and third, and…), Windows Modern applications look nothing like apps on Mac, iOS, Android or any other platform; right out of the gate, we had our work cut out for us and we had to decide how to balance the unique Windows Modern style with what has come to be recognized as the 1Password style. In the end, we decided to keep the Windows Modern app as true to the 1Password style as possible. Despite having to deal with an overly verbose pattern for overriding the style template (in some cases 100 lines of code just to change a single property for a button) we continued to customize nearly every area of the app; when the dust had finally settled, our shared stylesheet (for phone and desktop) was the largest single file in our entire project (~1200 lines of code).

But we were able to stay true to the 1Password brand, as evident in our lock screen:

So it was well worth the effort, and we certainly learned a few new tricks along the way! But styling with such reckless abandon does have a cost.

There will be blood (and hacks)

Issues first began to arise when we started testing theme-switching for Windows Phone. Windows Phone gives users the ability to switch between a dark and a light theme. This is a hallmark feature of Windows Phone and one that users have come to expect. But of course, this feature is only available on Windows Phone; the iOS and Android platforms don’t have this capability by default, which added a new wrinkle: do we introduce a feature on Windows Phone that is not available on our other mobile platforms? We also noticed very poor performance with accessibility features when using high-contrast themes, and ease-of-access font scaling had a very low ceiling before the majority of text was cut off.

Why did we perform so poorly? In part, it was because of all the customization we had done. We became so focused on achieving the 1Password look and feel that we customized nearly everything, including many things that we never needed to touch. We also used the RequestedTheme property heavily, which allowed us to force a page to always render in a specific theme; this is a big no-no for a universal app. But more than anything else, it’s how the platform handles custom styles. The moment you create a custom style, you’re entirely accountable for it: you must tell it exactly how to behave under every single scenario a user may throw at you; and on the Windows Modern platform, there are a lot of possible scenarios. There are two default themes for Windows Phone (and two other high-contrast themes), and Windows desktop has the default theme (not light, not dark, just right) along with four other high-contrast themes. Yep, that’s eight themes developers need to support when they choose to add some of their own styling and branding to their apps. The moment you decide to change a background colour, adjust a font’s opacity, or change letter spacing, you’re abandoned by the Windows app platform, and left to your own devices. This desertion isn’t too much of an issue for developers working primarily on Windows modern, as the support the platform gives you to handle all of these scenarios right out of the box is excellent. But it’s an unfeasible expectation for Windows to extend this support to developers who customize their apps so heavily, so we got to work and began getting our stylesheets under control.

The taming of the shrew

After all of our customization, we had to take a step back and see how we could make 1Password work with the Windows Modern ecosystem, instead of against it.

We had no desire to rewrite all of the styles and themes that Microsoft had given us for free with the operating system. The code was ready and available; all we had to do was let the platform do its work without losing our brand in the platform.

Our first order of business was getting our stylesheets under control. We went through the entire app, page by page, and removed any properties we could live without, thereby giving responsibility back to Windows. We then rebuilt support for all the missing themes by first including them explicitly in our stylesheets, and only overriding the system colors in the default or base theme; for high contrast and light/dark themes, we once again passed responsibility back to Windows.

Alternatives

Prior to coming to work at AgileBits, I gained a lot of experience working on web accessibility for the Canadian Government, and we often discussed how different platforms handled accessibility.  On the Mac, instead of separate themes, users are given sliders in the OS preferences to adjust contrast and invert colours when necessary. Keeping these preferences at the OS level takes a lot of the responsibility away from app developers. While it can seem a bit daunting to oversee eight themes (at least) on Windows, the aesthetic and practical usefulness of these themes cannot be denied. For example, users can create custom themes that can be saved to their profile and be made available on the different PCs they use. Also, these themes being predefined make selecting appropriate themes much easier for users.

Conclusion

Branding is a promise. This is our endless waltz, and we cannot fail our dance partners. It’s a delicate balance that we must strike between Windows Modern and the 1Password experience, so that we may engender harmony among 1Password and Windows users.