Developing an OAuth Sample for Adobe Photoshop

Editor’s Note: “This week’s guest post is by Ayan Choudhary, an Electrical Engineering student graduating in 2022 who took part in the Major League Hacking Fellowship program. Over the 12 week program, Ayan developed the OAuth workflow plugin sample for Adobe Photoshop.” — Erin Finnegan, Community Engineer, Adobe Creative Cloud

︎An image from Adobe Stock.

︎An image from Adobe Stock.

This post is for plugin developers who have a little experience with coding and who are familiar with Adobe Photoshop and Photoshop plugins.

One of the long standing demands from the developer community was for an oauth sample for Photoshop (using UXP) demonstrating how to connect an oauth workflow with a plugin. During my time as an MLH fellow, I decided to take on this task by creating a developer-friendly sample demonstrating how to connect an oauth workflow with a Photoshop UXP plugin.

What exactly is OAuth?

OAuth is an open standard for access delegation, commonly used as a way for Internet users to grant websites or applications access to their information on other websites but without giving them the passwords. This mechanism is widely used to permit the users to share information about their accounts with third party applications or websites.

Generally, OAuth provides clients a “secure delegated access” to server resources on behalf of a resource owner. It specifies a process for resource owners to authorize third-party access to their server resources without providing credentials. Designed specifically to work with Hypertext Transfer Protocol (HTTP), OAuth essentially allows access tokens to be issued to third-party clients by an authorization server, with the approval of the resource owner. The third party then uses the access token to access the protected resources hosted by the resource server.

Plugin Structure:

The structure of this plugin sample contains all the essential parts which include:

  1. Your Photoshop plugin
  2. Your server endpoints (for this development example, we’ll create a local Node.js server)
  3. The service providers OAuth endpoints (for this example, the Dropbox API)

︎Simple API based communication model

︎Simple API based communication model

Workflow Overview:

The high-level workflow is as follows:

  1. The Photoshop plugin pings the server to get the session ID.
  2. The server returns a unique ID for the user’s Photoshop session.
  3. The Plugin opens a tab in the user’s default browser with a URL pointing to an endpoint on the server.
  4. The server handles the entire OAuth code grant workflow.
  5. The user gives necessary permissions to the plugin.
  6. The server saves the access token paired with the session ID.
  7. The plugin polls the server to check if the access token is available for the session ID. If the token is available, the server sends the access token back.
  8. The plugin uses the access token to make API calls to the service API.

Implementation Details:

The Photoshop plugin

Starting with the Photoshop plugin, I had to design a UI that could call the connect handler, connect, and then change the UI to provide methods to fetch information from the OAuth client. The UI should display whether the OAuth service is connected or not. Also, since this is a developer-friendly sample, I decided to use a minimalistic layout to avoid unnecessary components.

︎UI design before OAuth connection

︎UI design before OAuth connection

︎UI design after OAuth connection

︎UI design after OAuth connection

My plugin uses Adobe spectrum UI components in a panel-based layout. I used standard v4 manifest format with an index.html as the entrypoint:

https://gist.github.com/ayanchoudhary/eb66ca42be88f82f9f2fdccdd90d6e8e#file-manifest-json

Next, we need to implement the logic for the UI elements. As soon as the user clicks the Connect OAuth button we open up a browser tab and call the backend route for logging in to the Dropbox client which delivers the userToken to the server. Then we set up a polling service to fetch the token from the backend.

Let’s have a look at the polling logic:

https://gist.github.com/ayanchoudhary/5164d7ee460af6cb52e6cdf1fb8400a8#file-polling-js

To open the browser tab we use the UXP library and the openExternal function:

// opens the url in the default browser
require(“uxp”).shell.openExternal(`${publicUrl}/login?requestId=${rid}`)

Once we receive the userToken from the backend server we can fetch the user’s information from the Dropbox API.

The next step involves setting up the Dropbox OAuth service so that we can interact with the Dropbox API.

Configuring the OAuth Provider (Dropbox)

Before we proceed to the backend server, we have to configure our OAuth provider, in this case, Dropbox. The following steps will set up the Dropbox side of things:

  1. Go to the Dropbox App Registration page and create a new app with the access level set to Full Dropbox.
  2. Under Redirect URIs in the OAuth2 subsection, add http://localhost:8000/callback as an entry.
  3. Copy the App key and App secret.

︎Sample field input for Redirect URIs

︎Sample field input for Redirect URIs

Now we have the Dropbox OAuth provider set up to listen to our server and respond with the required data.

The Backend Server

The backend server handles most of the work related to the connection with the Dropbox service and getting the userToken. We use a session-based model to separate multiple calls from different clients and make sure the correct token is delivered to each client. The sessionId will also be used as the requestId in the Dropbox requests.

https://gist.github.com/ayanchoudhary/ffd436b446b447ada7c3030df9cbbe03#file-session-js

We will also need the App key and App secret to make the connection with the Dropbox API. Place the key and secret in the config.js file and reference them when you connect with the Dropbox API.

https://gist.github.com/ayanchoudhary/a5169feb55f172ef66fa2ea7daed25c9#file-config-js

We will setup four routes for the interactions from the plugin and the Dropbox service:

This route will be invoked by the plugin in a new browser tab. It will redirect the user to the authorization page of the Dropbox service where the user can login and authorize the application.

We specified this route is in the Dropbox configuration earlier. Once the user successfully authorizes the application, Dropbox redirects to this URL with the userToken. We can then check for authenticity and pass it on to the plugin.

https://gist.github.com/ayanchoudhary/41679e4e36953ebe3a53c2e65744bc52#file-callback-js

This route simulates a database and stores the userToken in map with the appropriate sessionId to directly fetch the userToken without having the user sign in again and again.

This endpoint is continuously polled by the plugin to fetch the userToken from the simulated database and return it to the plugin.

Success!

At this point we have successfully connected with the OAuth service, fetched the token and returned it to the plugin. Now we can use this token to fetch the user information and other details from the Dropbox API and display it on the plugin UI.

Yahoo!! It was a long journey, but we finally made it. We have a working plugin sample for the oauth workflow for Photoshop. You can visit all the code here.

I can’t wait to hear your thoughts on it! Leave a comment on this article, or in the github repo. If you’re feeling adventurous, why not submit your own open-source sample to the Photoshop repo, or even apply to become an MLH Fellow.

For more stories like this, subscribe to our Creative Cloud Developer Newsletter.