Posting to social media from GitHub Actions

February 21st 2025 GitHub

The final step in my efforts to automatically announce new blog posts to social media from GitHub Actions was the actual act of posting the prepared message to selected social media platforms. After a bit of search and testing, I managed to find existing actions for all my platforms of interest.

For Mastodon, I chose the cbrgm/mastodon-github-action:

- name: Post message to Mastodon
  if: ${{ env.NEW_POST == 'true' }}
  continue-on-error: true
  uses: cbrgm/mastodon-github-action@v2
  with:
    url: ${{ secrets.MASTODON_URL }}
    access-token: ${{ secrets.MASTODON_ACCESS_TOKEN }}
    message: ${{ steps.social-media-message.outputs.message }}

In addition to the obvious message input, which I set to my precomposed message, I had to set the following secrets for authentication:

  • MASTODON_URL: the domain of my Mastodon instance, e.g., https://mas.to.
  • MASTODON_ACCESS_TOKEN: the access token, created via the New application button on the Preferences > Development page in the Mastodon web interface. I only had to grant the write:statuses scope. I had to use the generated value for Your access token: Create a new Mastodon application Access token for a Mastodon application

You might have also noticed that I set the continue-on-error property of the step to true. I did this for all actions, which attempt to post an update to social media. Even if one of them fails, I want the remaining ones to post to the other platforms.

For Bluesky, I chose myConsciousness/bluesky-post:

- name: Post message to Bluesky
  if: ${{ env.NEW_POST == 'true' }}
  continue-on-error: true
  uses: myConsciousness/bluesky-post@v5
  with:
    identifier: ${{ secrets.BLUESKY_IDENTIFIER }}
    password: ${{ secrets.BLUESKY_PASSWORD }}
    text: ${{ steps.social-media-message.outputs.message }}
    link-preview-url: ${{ env.POST_URL }}

Here, the precomposed message is set to text. But for the link in the message to work, I also had to set it as link-preview-url. This also ensured that a preview card was generated. Bluesky API authentication currently requires your username and password, so that's what I had to store in the secrets:

  • BLUESKY_IDENTIFIER: my Bluesky handle.
  • BLUESKY_PASSWORD: the password I log into Bluesky with.

For X, I chose rg-wood/send-tweet-action:

- name: Post message to X
  if: ${{ env.NEW_POST == 'true' }}
  continue-on-error: true
  uses: rg-wood/send-tweet-action@v1
  with:
    consumer-key: ${{ secrets.X_CONSUMER_API_KEY }}
    consumer-secret: ${{ secrets.X_CONSUMER_API_SECRET }}
    access-token: ${{ secrets.X_ACCESS_TOKEN }}
    access-token-secret: ${{ secrets.X_ACCESS_TOKEN_SECRET }}
    status: ${{ steps.social-media-message.outputs.message }}

The status input is set to my precomposed message. All the others are set to secrets with my authentication data. To get it, I first had to sign up for the Free API package:

Free API package for X

This automatically created for me the only project and app I am entitled to. I renamed both to make it more obvious to me what I am using them for.

The more important part of the configuration was changing the permissions. By default, the app was configured with read permissions only. I could change that in User authentication settings on the app Settings tab:

  • I changed App permissions from Read to Read and write.
  • I set the Type of app to Web app, Automated App or Bot. (I think my use case is best categorized as a bot.) Before I was allowed to Save the changes, I also had to fill out the Callback URI / Redirect URL and Website URL fields, although they aren't really applicable in my case.

Authentication settings for X application

Only then was I ready to get the authentication data I needed from the Keys and tokens tab:

  • X_CONSUMER_API_KEY and X_CONSUMER_API_SECRET: They can only be accessed once, after you click the Regenerate button for API Key and Secret in the Consumer Keys section. (Of course, this action invalidates any previously generated API key and secret.) Consumer keys for X application
  • X_ACCESS_TOKEN and X_ACCESS_TOKEN_SECRET: They can also only be accessed once, after you click the Regenerate button for Access Token and Secret in the Authentication Tokens section. This is where you should make sure that they were generated with Read and Write permissions or the GitHub action will fail with a 403 error. (Of course, this action invalidates any previously generated access token and secret.) Authentication tokens for X application

With this, I have covered all the social media platforms, I wanted to post to. The chosen actions did everything I required them to, so I didn't have to write any code to interact with the APIs directly. For certain, this has saved me a lot of time and effort.

Get notified when a new blog post is published (usually every Friday):

Copyright
Creative Commons License