I managed to get Mastodon SAML sign-ins working with Keycloak. Since I never bothered to learn anything about SAML, this made it difficult. But I persevered. I would like to share what finally made it work.

Mastodon

Mastodon’s .env.production file:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
SAML_ENABLED=true
SAML_ACS_URL=https://{your mastodon server}/auth/auth/saml/callback
SAML_ISSUER=mastodon
SAML_IDP_SSO_TARGET_URL=https://{your keycloak server}/auth/realms/{your realm}/protocol/saml
SAML_IDP_CERT=-----BEGIN CERTIFICATE-----MIIC...QKML-----END CERTIFICATE----- 
#SAML_IDP_CERT_FINGERPRINT=
SAML_NAME_IDENTIFIER_FORMAT=urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
#SAML_CERT=
#SAML_PRIVATE_KEY=
SAML_SECURITY_WANT_ASSERTION_SIGNED=true
#SAML_SECURITY_WANT_ASSERTION_ENCRYPTED=true
SAML_SECURITY_ASSUME_EMAIL_IS_VERIFIED=true
SAML_ATTRIBUTES_STATEMENTS_UID=uid
SAML_ATTRIBUTES_STATEMENTS_EMAIL=email
#SAML_ATTRIBUTES_STATEMENTS_FULL_NAME="urn:oid:2.16.840.1.113730.3.1.241"
SAML_ATTRIBUTES_STATEMENTS_FIRST_NAME=first_name
SAML_ATTRIBUTES_STATEMENTS_LAST_NAME=last_name
#SAML_UID_ATTRIBUTE=uid
#SAML_ATTRIBUTES_STATEMENTS_VERIFIED=
#SAML_ATTRIBUTES_STATEMENTS_VERIFIED_EMAIL=

Get the SAML_IDP_CERT from Keycloak’s Realm Settings -> Keys -> Certificate

Keycloak

Create a new SAML client with the following:

Settings

FieldValue
Client IDmastodon
Include AuthnStatementON
Sign DocumentsON
Sign AssertionsON
Name ID Formatusername
Valid Redirect URIshttps://{your mastodon server}/auth/auth/saml/callback
Base URLhttps://{your mastodon server}

Mappers

Mapper TypePropertySAML Attribute NameSAML Attribute NameFormat
User PropertylastNamelast_nameBasic
User PropertyemailemailBasic
User PropertyfirstNamefirst_nameBasic
User PropertyuiduidBasic

You could probably turn on Encrypted Assertions if you filled in the SAML_CERT and SAML_PRIVATE_KEY for Mastodon.

Keep in mind this is just one way of setting it up and naming the fields. But after looking at Mastodon’s code and both servers’ debug logs for a while, this seems to work for me.