Skip to content

Mastodon as a identity source #4193

Open
@vitunvuohi

Description

@vitunvuohi

Is your feature request related to a problem? Please describe.
It would be fantastic to hook authentik up to a particular mastodon instance to allow for oauth signin. This might also work for other fediverse social platforms like Pleroma.

Describe the solution you'd like
Add mastodon as a potential source for federation and social login. I think the code would be something roughly like the attached (but I am not familiar enough to test it, so I don't have a specific PR)

Describe alternatives you've considered
I have tried setting it up as an oidc connection to test, but that is not quite ideal as mastodon only supports oauth2 and not full oidc. Things like username don't automatically populate. I thought about making my own build for authentik but I don't think I know enough to do that yet 😞 .

Additional context
Here is roughly what I think might work for Mastodon? Then an admin could simply paste the URLs of their instance, after creating a new developer application to get the client key and id:
https://[instance]/oauth/authorize
https://[instance]/oauth/token
https://[instance]/api/v1/accounts/verify_credentials for profile

class MastodonClient(OAuth2Client):
    """Mastodon OAuth2 Client"""

    def get_access_token(self, **request_kwargs):
        "Fetch access token from callback request."
        auth = HTTPBasicAuth(self.source.consumer_key, self.source.consumer_secret)
        return super().get_access_token(auth=auth)

class MastodonOAuthRedirect(OAuthRedirect):
    """Mastodon OAuth2 Redirect"""

    def get_additional_parameters(self, source: OAuthSource):  # pragma: no cover
        return {
            "scope": ["read"]
        }


class MastodonOAuth2Callback(OAuthCallback):
    """Mastodon OAuth2 Callback"""

    client_class = MastodonClient
    
    def get_user_id(self, info: dict[str, str]) -> str:
        return info.get("username", "")

    def get_user_enroll_context(
        self,
        info: dict[str, Any],
    ) -> dict[str, Any]:
        return {
            "username": info.get("username"),
            "name": info.get("display_name")
        }


@registry.register()
class MastodonType(SourceType):
    """Mastodon Type definition"""

    callback_view = MastodonOAuth2Callback
    redirect_view = MastodonOAuthRedirect
    name = "Mastodon"
    slug = "Mastodon"

    urls_customizable = True

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions