“Privacy protection is a key element of customer confidence and a pillar of sustainable digital business development.”
― Stéphane Nappo

Open Access signifies making your research data open to all. Your research datasets become more discoverable thus making other researchers aware of your research. Also this will amplify your research impact significantly. Zenodo is one such platform which makes the sharing, curation and publication of data and software a reality for all researchers.

Conversing regarding our own space - Our team decided to integrate Zenodo in one of our product. One of the product we are working is an Open Reuse platform which is an Open-Source project and also an Open-Science initiative where it enables researchers to publish their reuse/reproducibility efforts of the published research and make them recognisable.

https://www.smithsonianmag.com/science-nature/biomedical-science-studies-are-shockingly-hard-reproduce-180957708/

So the team decided to enable researchers to publish their data associated with their reuse/reproducibility efforts on Zenodo from within the OpenReuse platform, without the need to separately log into Zenodo for publishing their data. For this purpose, Zenodo provides a rich API which allows third ­party tools and services to use Zenodo majorily in the backend in their own workflows and is just a piece of cake to get this integrated by any developer.

The major holdback for the team in integrating Zenodo in the backend was our concern to provide a richer privacy to the user which is one of the team's hard-coded mantra's. Our team wasn't interested in storing user's personal data like contact information and log-in credentials of the third party tools, on our own databases, which would otherwise give us complete access to user's Zenodo account.  

Now the question was how to overcome this challenge!! Ahh the answer was - Frontend !! Isn't it quite straightforward ;)

Zenodo provides a guide to use it's REST API in python which is potentially a guide for third party app developers to integrate it in the backend for which there is a need to post the user's tokens to the backend. Unlikely as we never wished to post the credential tokens to our own servers, we decided to use it in jQuery (Potentially in the client side without the need to send user's credentials to the backend/own servers).

So this is the procedure we followed with few simple steps and might enable others if you ever wish to integrate Zenodo in your applications using jQuery.

Practical Demo

  1. Provide an option in your application to login with Zenodo.
    Screen-Shot-2018-09-14-at-9.58.05-PM-1

  2. When user clicks on Login button, zenodo oauth API is called, it authenticates the user and returns the 'access token'. A personal access token works just like a normal OAuth access token for authentication against the API. It is shown below that how to call Zenodo auth api.

    <a target="_blank" href="https://zenodo.org/oauth/authorize?scope=deposit:write+deposit:actions&state=CHANGEME&redirect_uri=<redirect_page_uri>&response_type=code&client_id=<client_id>">
        Login With Zenodo
    </a>
    

    Here, in 'href' attribute, a 'GET' request has been made to zenodo oauth API (https://zenodo.org/oauth/authorize) having these parameters -

    • scope - Scopes assign permissions to your personal access token to limit access to data and actions in Zenodo. The possible values of scope are :
     1. deposit:actions - Allow publishing of uploads.
     2. deposit:write - Allow upload (but not publishing).
     3. user:email - Allow access to email address (read-only).  
    
    • state - 'CHANGEME'
    • response_type - 'code'
    • client_id - <your_own_client_id>
    • redirect_uri - <your_own_redirect_uri> : This is the url of the page in your application, where Zenodo will redirect the user after authenticating. (For ex. in my application - https://openreuse.org/zenodo_callback.html) In this page you can show loader and execute the below script to get access token.
    // zenodo_callback.html
    
     $.ajax({
         url: '/backend/zenodo_token_callback',
         dataType: 'json',
         data: {
             'code': <your_own_code>   //described below
         },
         success: function(data){
             localStorage.setItem("zenodo_application_token", data.access_token);
             window.close();
         }
     });
    

    Note : Here we are calling an API which is written in our backend as if called in frontend, this will reveal your client secret to the users. Also we are not saving access token in backend, we're just returning the response to clientside. So whenever user logs in, he'll have to re-authorize himself. Call this api (https://zenodo.org/oauth/token) in backend & get access token in 'zenodo_callback.html'. I'm using python here in backend. You can use any language in which you are comfortable.

    @app.route('/backend/zenodo_token_callback')
    def zenodo_callback():
        code = request.args.get('code', '')
        r = requests.post("https://zenodo.org/oauth/token",
              data = {
                  'client_id': <your_own_client_id>,
                  'client_secret': <your_own_client_secret>,
                  'grant_type': 'authorization_code',
                  'code' : <your_own_code>,
                  'redirect_uri': <your_own_redirect_uri>
              }
            )
        data = r.json()
        return app.response_class(
            response=json.dumps(data),
            status=200,
            mimetype='application/json'
        )
    

    Here, 'client_id' and 'client_secret' are the keys which you get after signing in with a developers account on Zenodo. The 'code' comes from the parameter of the url of the current page, i.e. redirect page. Don't get confused. Here's the flow.

    • You click on Login button
    • Zenodo oauth api is called and an authorization window opens!Screen-Shot-2018-09-19-at-12.32.02-PM
    • You click on 'Authorize Application' button.
    • This redirects you to the page whose url you passed in the 'redirect_uri'. Also it appends 'code' in the url. (For ex. https://openreuse.org/zenodo_callback.html?code=W6qVexybyUio8mHzU4FBy8W51XONS)
    • Now you are on the redirected page. Here, first you retrieve 'code' from url & make an AJAX call passing the above code & you get access token in response.
    • Now set that access token in local storage to be used further for user authentication.
    • Also close the window & come back to your application page.
  3. Now you have access token stored in localstorage. Call the Zenodo api to create a new upload.

    access_token = localStorage.getItem("zenodo_application_token");
    var articleData = {
         'metadata': {
             'title': 'My First Article',
             'upload_type': 'dataset',
             'description': 'This is my first upload'
         }
    };
    $.ajax
     ({
         type: "POST",
         url: "https://zenodo.org/api/deposit/depositions",
         data : JSON.stringify(articleData),
         dataType: 'json',
         async: true,
         beforeSend: function (xhr){
             xhr.setRequestHeader("Content-Type", "application/json");
             xhr.setRequestHeader('Authorization', 'Bearer ' + access_token);
         },
         success: function (data){
             deposition_id = data['id'];
         }
     });
    

    The response of above api call is as shown :

        {
          "conceptrecid": "1419271", 
          "created": "2018-09-14T19:38:05.283385+00:00", 
          "files": [], 
          "id": 1419272, 
          "links": {
                "bucket": "https://zenodo.org/api/files/c22c9a33-8886-4cfc-a44a-bf27ae6469be", 
                "discard": "https://zenodo.org/api/deposit/depositions/1419272/actions/discard", 
                "edit": "https://zenodo.org/api/deposit/depositions/1419272/actions/edit", 
                "files": "https://zenodo.org/api/deposit/depositions/1419272/files", 
                "html": "https://zenodo.org/deposit/1419272", 
                "latest_draft": "https://zenodo.org/api/deposit/depositions/1419272", 
                "latest_draft_html": "https://zenodo.org/deposit/depositions/1419272", 
                "publish": "https://zenodo.org/api/deposit/depositions/1419272/actions/publish", 
                "self": "https://zenodo.org/api/deposit/depositions/1419272"
             }, 
          "metadata": {
              "access_right": "open", 
              "creators": [
                  {
                    "affiliation": "Zenodo", 
                    "name": "Manisha"
                  }
                ], 
              "description": "This is my first upload", 
              "license": "CC0-1.0", 
              "prereserve_doi": {
                  "doi": "10.5281/zenodo.1419272", 
                  "recid": 1419272
               }, 
              "publication_date": "2018-09-14", 
              "title": "My First Article", 
              "upload_type": "dataset"
          }, 
         "modified": "2018-09-14T19:38:05.283393+00:00", 
         "owner": 48521, 
         "record_id": 1419272, 
         "state": "unsubmitted", 
         "submitted": false, 
         "title": "My First Article"
    }
    
    
    
  4. From the above API call, you get article id in response. Now upload file data on this id.

    access_token = localStorage.getItem("zenodo_application_token");
    var deposition_id = data['id'];  // From above api call
    var file = $('input[type=file]')[0].files[0];
    var fd = new FormData();
    fd.append( 'file', file);
    $.ajax
      ({
        type: "POST",
        url: "https://zenodo.org/api/deposit/depositions/" + deposition_id + "/files",
        data: fd,
        processData: false,
        contentType: false,
        beforeSend: function (xhr) {
            xhr.setRequestHeader('Authorization', 'Bearer ' + access_token);
        },
        success: function (response) {
            //uploaded file information
        }
      });
    
  5. You can also publish your article to make it public.

    Don’t execute this last step - it will put your test upload straight online. Once published and is assigned a DOI, you can't remove from there.

    var deposition_id = data['id'];  // From the api call executed in 3rd step
    $.ajax
        ({
            type: "POST",
            url: "https://zenodo.org/api/deposit/depositions/" + zenodo_deposition_id + "/actions/publish",
            beforeSend: function (xhr){
                xhr.setRequestHeader('Authorization', 'Bearer ' + zenodo_token);
            },
            success: function (data) {
                console.log("zenodo article published :", data);
            }
        });
    

And that's it !!! Your data has been successfully uploaded to Zenodo.

Expectations and Outcomes:

  1. We never wanted to store user's credentials tokens on our servers. So Integrating Zenodo using JQuery in the client side enabled us to achieve this task without the need for posting the access tokens to our servers, The tokens that are stored in the local storage within the user's browsers will be expired once the session ends.
  2. The application will only have access to that data which user is allowing the application to access and that too until the session is expired. If user logs out and logs in again, he should have to re-authorize himself.

Here's a link to a demo which you can try an hand's on. And if you are a researcher and wish to get your reuse efforts recognised, please signup on OpenReuse to experience this yourself.  

For code reference of this practical demo, you can follow this link to a Github repository of the demo -  Code Reference

For any queries or suggestions, please feel free to reach out to me.

We are currently integrating Figshare which is also a widely used data repository across the community. Watch out for our upcoming article for the same. (Figshare Integration - A care for user's privacy and their experience)


References:

  1. https://scholarlykitchen.sspnet.org/2018/08/23/new-plugins-kopernio-unpaywall-pursuing/
  2. https://inc42.com/buzz/facebook-login-breached/
  3. https://ra21.org/index.php/what-is-ra21/ra21-position-statement-on-access-brokers/
  4. https://thehackernews.com/2017/02/password-manager-apps.html
  5. https://scholarlykitchen.sspnet.org/2016/05/19/sci-hub-and-academic-identity-theft-an-open-letter-to-university-faculty-everywhere/