zgtangqian.com

Zenodo Integration: Protecting User Privacy While Enhancing Experience

Written on

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

Open Access refers to the practice of making research data available to everyone. By doing so, your datasets become easier to find, increasing awareness among other researchers and significantly boosting the impact of your work. Zenodo serves as a platform that facilitates the sharing, curation, and publication of data and software for all researchers.

Focusing on our project, our team made the decision to incorporate Zenodo into one of our offerings. We are developing an Open Reuse platform, an Open-Source initiative aimed at enabling researchers to share their efforts in reusing and reproducing published research, thereby enhancing its visibility.

To streamline the process, our team decided to allow researchers to publish their data related to reuse and reproducibility efforts directly on Zenodo through the OpenReuse platform, eliminating the need to log in separately. Zenodo offers a comprehensive API that facilitates easy integration for developers looking to incorporate its functionalities into their workflows.

> Our main challenge was ensuring robust privacy for users, a principle our team prioritizes. We were not inclined to store personal details such as contact information or login credentials from third-party tools in our database, as this would provide us with unnecessary access to users' Zenodo accounts.

The solution to this challenge was straightforward: we opted for a Frontend approach.

Zenodo provides a Python guide for utilizing its REST API, which assists third-party developers in backend integration while requiring user tokens for authentication. However, since we aimed to avoid sending user credentials to our servers, we chose to implement it using jQuery on the client side.

Here’s the simplified process we followed, which could help others interested in integrating Zenodo into their applications with jQuery.

Practical Demonstration

  1. Include an option for users to log in via Zenodo.

  2. Upon clicking the login button, the Zenodo OAuth API is triggered, authenticating the user and providing an access token. This token functions similarly to a standard OAuth access token for API authentication. Here’s how to call the Zenodo authentication 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>

    The href attribute makes a GET request to the Zenodo OAuth API (https://zenodo.org/oauth/authorize) with the following parameters:

    • scope: Specifies permissions for the personal access token to limit data and action access in Zenodo. Possible scope values include:
      1. deposit:actions - Allows publishing uploads.
      2. deposit:write - Allows uploads (not publishing).
      3. user:email - Grants access to the 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 in your application where Zenodo redirects users post-authentication (e.g., https://openreuse.org/zenodo_callback.html). This page can display a loader while executing the script to retrieve the 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: The API called in our backend prevents revealing the client secret to users. We also do not store the access token on the backend, merely returning the response to the client side. Therefore, users will need to re-authorize themselves upon each login. Call the API (https://zenodo.org/oauth/token) on the backend to obtain the access token in zenodo_callback.html. I'm using Python here, but you can use any programming language of your choice.

@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'

)

The client_id and client_secret are obtained after registering for a developer account on Zenodo. The code is derived from the redirect page URL parameter.

Flow Overview

  • Click the Login button.
  • The Zenodo OAuth API is called, and an authorization window appears.
  • Click the ‘Authorize Application’ button.
  • This redirects you to the URL provided in the redirect_uri, appending the code to the URL (e.g., https://openreuse.org/zenodo_callback.html?code=W6qVexybyUio8mHzU4FBy8W51XONS).
  • Retrieve the code from the URL on the redirected page and make an AJAX call using this code to receive the access token.
  • Store the access token in local storage for further authentication.
  • Close the window and return to your application page.
  1. With the access token saved in local storage, 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 from the API call will look like this:

{

"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"

}

  1. From the API response, extract the article ID and upload the file data using this ID.

    access_token = localStorage.getItem("zenodo_application_token");

    var deposition_id = data['id']; // From the previous 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

    }

    });

  2. You can publish your article to make it publicly accessible.

> Caution: Be careful with this last step, as it will publish your test upload online. Once published and assigned a DOI, it cannot be removed.

var deposition_id = data['id']; // From the API call executed in the third 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 is successfully uploaded to Zenodo.

Expectations and Outcomes:

  1. We aimed to avoid storing user credential tokens on our servers. By integrating Zenodo using jQuery on the client side, we achieved this goal without needing to transmit the access tokens to our servers. Tokens stored in local storage will expire once the session concludes.
  2. The application only accesses data that the user permits, and only while the session is active. If the user logs out and logs back in, they must re-authorize themselves.

Here’s a link to a demo for hands-on experience. If you're a researcher looking to have your reuse efforts recognized, please sign up on OpenReuse to explore this for yourself.

For code references related to this practical demonstration, visit this GitHub repository — Code Reference.

If you have any questions or suggestions, feel free to reach out to me.

Share the page:

Twitter Facebook Reddit LinkIn

-----------------------

Recent Post:

The Fascinating Appeal of Deer Lungs in Science Education

Exploring the unique educational value of deer lungs in teaching biology and the memorable moments they create.

The Quest for Perfection: Rediscovering Our Inner Genius

Exploring the lost art of perfectionism and its significance in today's world.

A Candid Reflection on My Tumultuous Marriage Journey

A heartfelt look back at the regrets of staying in a troubled marriage and the lessons learned from it.

Harnessing PowerShell for Wildfire Data Collection

Explore how to use PowerShell to gather real-time wildfire data, enhancing understanding and response efforts.

The Detective's Mindset in Software Development

Exploring the parallels between detective work and software development through various professions.

Essential Strategies for New Writers: Insights from My Initial Two Months on Medium

Discover key strategies for new writers based on two months of experience on Medium. Gain insights to enhance your writing journey.

# The Dark History of Castrati: Beauty and Brutality Intertwined

Explore the tragic history of castrati, from their creation to their unique vocal talents and the societal implications of their existence.

Harnessing Generative AI to Revolutionize Business Practices

Exploring how generative AI tools like AnswerChatAI can transform business document processing and information retrieval.