If you're not in the know, a pretty decent amount of people on Twitter have been migrating over to the Fediverse via Mastodon (including me). As this is a new platform to many, maybe you happen to have a Power Automate flow which posts a link to your latest blog post through various social media sites (me). Now you want to be able to throw Mastodon into the mix. How do we accomplish this?
Let's make a Custom Connector in Power Automate!
NOTE: You will need a Power Automate subscription to create custom connectors. You can sign up for a 90-day trial when prompted or use a developer subscription. Yes, I know exactly what you're saying right now...
Prerequisites
- Power Automate Account
- Mastodon account on an instance that allows you to create OAuth client applications.
- Mastodon API Docs
Getting Started
The first thing that needs to be done is creating the OAuth client app that Power Automate is going to be connect with and issue authenticated REST API calls on your behalf.
Create Client App in Mastodon
Assuming you've signed into your Mastodon instance, go to the settings page and click on the Development link.
https://{yourmastodoninstance}/settings/applications
Click the New Application button to begin.
Fill out the Application Name with your desired name. This will be displayed to identify the client where this post originated from. For example, "Web" will be the client used if you're posting from the Mastodon instance in a web browser.
Add https://global.consent.azure-apim.net/redirect
on the next line in the Redirect URI section. This is the URL used when you configure your OAuth connection within Power Automate.
To post a "toot" on your timeline, the write:statuses
scope is required.
Once you've finished creating the application, the Client Key and Client Secret will be available for use.
Add Custom Connector for Mastodon
For this part, we'll be in the Power Automate interface.
I'll let you choose your destiny at this point in time. Walk through the manual steps of creating a custom connector from scratch, or import the result.
From Scratch
Here's the step by step on how to create this from scratch.
Why from scratch? There's no official OpenAPI document for the Mastodon API, and the few unofficial ones that exist require so much extra manual work.
Head over to https://make.powerautomate.com. Expand the Data menu and click on Custom Connectors
Select Create from blank from the New custom connector menu
Choose a name for your connector. In this example, we'll use Mastodon API. Press Continue.
You should see a connector configuration screen with 5 steps: General, Security, Definition, Code (preview), and Test.
1. General
This step is used for configuring the base piece of the connector.
Upload Connector icon
Optional.
Icon background color
Optional.
Description
Optional, but useful to describe what this connector does.
Scheme
HTTPS
Host
Set this to the domain of the Mastodon instance you're joined to, without the https:// in front of it
Base URL
Leave this as / for now
2. Security
The security section is where you will configure authentication to the connector.
The Authentication Type portion contains a dropdown that includes many authentication provider options. Select OAuth 2.0 as the authentication option.
Fill out OAuth 2.0 configuration options:
Identity Provider
Generic OAuth 2.0
Client Id
Client Key generated from Mastodon
Client Secret
Client Secret generated from Mastodon
Authorization Url
The OAuth Authorization Url endpoint for Mastodon instances is a relative path of /oauth/authorize
.
For example: https://mastodon.instance/oauth/authorize
Token URL
Relative path of /oauth/token
Refresh URL
Use the Token URL for this
Scope
Use write:statuses
for the scope.
Redirect URL
The Redirect URL will show once the connector is saved. It's usually the same url you configured for use in the Mastodon client app.
Your security configuration is complete.
3. Definition
You can define actions for your custom connector in the Definition section. These actions can be invoked individually from the custom connector and represent REST API calls.
For writing statuses using the Mastodon API, we will create an action that uses the statuses API. This API can be used by sending the status
form-data parameter as JSON as an HTTP POST to /api/v1/statuses
POST https://mastodon.example/api/v1/statuses
Content-Type: application/json
{
"status": "Some status text"
}
Press the (+) New Action link under the Action section on the left.
Under General, we can use information from the statuses
API to fill in the information needed for the action.
Summary
Publish new status
Description
Post a new status.
Operation ID
Post/api/v1/statuses
Now we're ready to configure the Request. Scroll down to the next section and click on + Import from sample
Verb
POST
URL
/api/v1/statuses
Body
{
"status": "Some status text"
}
The request is now configured to properly send data to the statuses endpoint, but how do you handle the response data?
According to the API definition, the statuses
API for creating new posts must handle 200: OK
, 401: Unauthorized
, and 422: Unprocessable entity
Status Codes.
Starting with the 200 response, click on the default
response under the Response section.
Change the Name to 200. Click the + Import from sample button
Headers
You can leave this blank, otherwise add Content-Type application/json
. By default, this will assume that you're sending POST body as JSON.
Body
Paste the example of the Status entity used as the return object of this API call.
Click the Import button to complete this section
The 200: OK response is complete.
Press the Back button above the Response section header.
To configure the 401 and 422 responses individually, click + Add Default Response. This will launch the same Import from sample dialog seen from the 200 process. Use either the examples for 401 or 422 as the Body.
Click the Import button. This will create a default response item. Click into it and modify the Name to the proper response code.
Repeat this process until you have all 3.
The Definition section is complete.
Click the button to Create the connector, then click the close button.
After about 15-20 seconds, refresh the Custom Connectors screen.
From here, click the + next to the newly created connector to initiate a Connection.
Login to your Mastodon instance and accept the OAuth consent.
You now have a successfully authenticated Mastodon API connection
Completed OpenAPI/Swagger code
This Swagger YAML can be either copy/pasted into the Swagger Editor from the Custom Connector wizard, or saved and imported by choosing Import from OpenAPI file in the New Custom Connector drop down.
After this is imported, go to the Security section of the connector and enter the Client Id and Client Secret that was generated from Mastodon in the initial steps above. Once you've saved the connector, you can create a connection from it and use it.
swagger: '2.0' | |
info: | |
title: Mastodon API | |
description: Mastodon API | |
version: '1.0' | |
host: mastodon.instance | |
basePath: / | |
schemes: | |
- https | |
consumes: [] | |
produces: [] | |
paths: | |
/api/v1/statuses: | |
post: | |
responses: | |
'200': | |
description: default | |
schema: | |
type: object | |
properties: | |
id: | |
type: string | |
description: id | |
created_at: | |
type: string | |
description: created_at | |
in_reply_to_id: | |
type: string | |
description: in_reply_to_id | |
in_reply_to_account_id: | |
type: string | |
description: in_reply_to_account_id | |
sensitive: | |
type: boolean | |
description: sensitive | |
spoiler_text: | |
type: string | |
description: spoiler_text | |
visibility: | |
type: string | |
description: visibility | |
language: | |
type: string | |
description: language | |
uri: | |
type: string | |
description: uri | |
url: | |
type: string | |
description: url | |
replies_count: | |
type: integer | |
format: int32 | |
description: replies_count | |
reblogs_count: | |
type: integer | |
format: int32 | |
description: reblogs_count | |
favourites_count: | |
type: integer | |
format: int32 | |
description: favourites_count | |
favourited: | |
type: boolean | |
description: favourited | |
reblogged: | |
type: boolean | |
description: reblogged | |
muted: | |
type: boolean | |
description: muted | |
bookmarked: | |
type: boolean | |
description: bookmarked | |
content: | |
type: string | |
description: content | |
reblog: | |
type: string | |
description: reblog | |
application: | |
type: object | |
properties: | |
name: | |
type: string | |
description: name | |
website: | |
type: string | |
description: website | |
description: application | |
account: | |
type: object | |
properties: | |
id: | |
type: string | |
description: id | |
username: | |
type: string | |
description: username | |
acct: | |
type: string | |
description: acct | |
display_name: | |
type: string | |
description: display_name | |
locked: | |
type: boolean | |
description: locked | |
bot: | |
type: boolean | |
description: bot | |
discoverable: | |
type: boolean | |
description: discoverable | |
group: | |
type: boolean | |
description: group | |
created_at: | |
type: string | |
description: created_at | |
note: | |
type: string | |
description: note | |
url: | |
type: string | |
description: url | |
avatar: | |
type: string | |
description: avatar | |
avatar_static: | |
type: string | |
description: avatar_static | |
header: | |
type: string | |
description: header | |
header_static: | |
type: string | |
description: header_static | |
followers_count: | |
type: integer | |
format: int32 | |
description: followers_count | |
following_count: | |
type: integer | |
format: int32 | |
description: following_count | |
statuses_count: | |
type: integer | |
format: int32 | |
description: statuses_count | |
last_status_at: | |
type: string | |
description: last_status_at | |
emojis: | |
type: array | |
items: {} | |
description: emojis | |
fields: | |
type: array | |
items: | |
type: object | |
properties: | |
name: | |
type: string | |
description: name | |
value: | |
type: string | |
description: value | |
verified_at: | |
type: string | |
description: verified_at | |
description: fields | |
description: account | |
media_attachments: | |
type: array | |
items: {} | |
description: media_attachments | |
mentions: | |
type: array | |
items: {} | |
description: mentions | |
tags: | |
type: array | |
items: {} | |
description: tags | |
emojis: | |
type: array | |
items: {} | |
description: emojis | |
card: | |
type: object | |
properties: | |
url: | |
type: string | |
description: url | |
title: | |
type: string | |
description: title | |
description: | |
type: string | |
description: description | |
type: | |
type: string | |
description: type | |
author_name: | |
type: string | |
description: author_name | |
author_url: | |
type: string | |
description: author_url | |
provider_name: | |
type: string | |
description: provider_name | |
provider_url: | |
type: string | |
description: provider_url | |
html: | |
type: string | |
description: html | |
width: | |
type: integer | |
format: int32 | |
description: width | |
height: | |
type: integer | |
format: int32 | |
description: height | |
image: | |
type: string | |
description: image | |
embed_url: | |
type: string | |
description: embed_url | |
description: card | |
poll: | |
type: string | |
description: poll | |
'401': | |
description: default | |
schema: | |
type: object | |
properties: | |
error: | |
type: string | |
description: error | |
'422': | |
description: default | |
schema: | |
type: object | |
properties: | |
error: | |
type: string | |
description: error | |
summary: Publish new status | |
description: Post a new status. | |
operationId: Post_api_v1_statuses | |
parameters: | |
- name: body | |
in: body | |
required: true | |
schema: | |
type: object | |
properties: | |
status: | |
type: string | |
description: status | |
title: status | |
definitions: {} | |
parameters: {} | |
responses: {} | |
securityDefinitions: | |
oauth2-auth: | |
type: oauth2 | |
flow: accessCode | |
authorizationUrl: https://mastodon.instance/oauth/authorize | |
tokenUrl: https://mastodon.instance/oauth/token | |
refreshUrl: https://mastodon.instance/oauth/token | |
scopes: | |
write:statuses: write:statuses | |
security: | |
- oauth2-auth: | |
- write:statuses | |
tags: [] |
Let's Test This Baby Out With a Power Automate Flow
I've created a simple Power Automate flow with a manual trigger. Then, I added a new step and selected the Publish new status Action from the Mastodon API custom connector.
I added a simple sentence to the status
property of the action: "Sup Mastodon! With love from #PowerAutomate 💯"
Saved the flow and kicked it off manually.
Alright! The flow completed successfully.
Did it actually work, though? 🤔
... ...
IT DID!
We have a successful Mastodon post driven by Power Automate!
Conclusion
This was a simple, fun, and detailed exercise to create a Custom Connector in Power Automate for REST APIs. Anyone can do this as long as the information for an API endpoint is known. Have fun cross-posting to Mastodon and other social media sites!