WriteFreely OAuth2 Integration

This document explains how to implement Monosign with WriteFreely, the open-source minimalist blogging platform. It covers Single Sign-On with OAuth 2.0, which is built into WriteFreely as the generic OAuth provider. WriteFreely uses the Authorization Code flow and reads the user from the user information endpoint, so the OIDC/OpenID access key of Monosign is used as an OAuth 2.0 provider. Before you continue, it is better to read the WriteFreely configuration documentation (section Generic OAuth).

This configuration is done with WriteFreely running on Docker Compose (image ghcr.io/writefreely/writefreely:latest, a develop build of September 2026). If your WriteFreely version or deployment type is different, please check the WriteFreely documentation.

WriteFreely supports OAuth 2.0 only. It does not validate an ID token (no issuer or nonce check), it does not use the discovery document and SAML is not available. There is no single sign-on screen in the WriteFreely admin panel; the provider is defined in the config.ini file.

Version requirement: use WriteFreely v0.17.2 or newer (or a develop build that contains the change “make OAuth Adapter RFC-compliant”). Older versions, including v0.17.1, send the client credentials twice (in the request body and in the HTTP Basic header). Monosign follows RFC 6749 section 2.3 (“the client MUST NOT use more than one authentication method in each request”) and rejects the token request with Multiple client credentials cannot be specified. WriteFreely then shows unable to exchange code for access token.

Monofor has no responsibility to do WriteFreely configurations. If you need support please contact the WriteFreely community or your WriteFreely support provider.

📑 Instructions

This documentation contains 5 main steps for integration.

  1. Creating an application on Monosign

  2. Configuring the OIDC/OpenID settings on Monosign

  3. Assign a user to the WriteFreely application

  4. Configuration Single Sign-On for WriteFreely

  5. Sign In Test

1- Creating an Application on Monosign

Create your application on Monosign first. Open the Applications page from the left menu and click Add New.

image-20261014-085131.png
Applications page in Monosign (1: Applications menu, 2: Add New)

WriteFreely is not in the application catalog, so click Create from scratch.

image-20261014-085216.png
Creating a new application from scratch (1: Create from scratch)

Fill in the application details on the Application tab and click Next.

image-20261014-085338.png
New Application - Application tab (1: Name, 2: Logo (optional), 3: Next)

Property

Value

Description

Name

WriteFreely

Name of the application shown to users on the Monosign portal and on the Monosign sign-in page.

Type

Web

WriteFreely is accessed through a web browser. Options: Web, Mobile, Desktop, API.

Url

Optional

Leave empty or enter the WriteFreely address so users can open the application from their Monosign portal.

Logo

Optional

Browse and upload a logo; it is also shown on the Monosign sign-in page.

Users can see this application on their list

Enabled

Displays the application on the user portal.

On the Access tab define who can reach the application and click Create Application.

image-20261014-085425.png
New Application - Access tab (1: Profile Access Type, 2: Create Application)

Property

Value

Description

User Access Type

System Default

Defines which users can access this application. Options: Only Assigned Users, All Users, System Default.

User Group Access Type

System Default

Defines the application’s user group access.

Source Using Type

System Default

Defines which user sources the application can use.

Profile Access Type

All

Defines which user profile attributes are available to the application (Options: Restricted, All). WriteFreely needs the user name, the name and the e-mail address of the user.

After the application is created, click Keys and add a new Access Key for OIDC/OpenID access.

image-20261014-085505.png
Keys tab of the WriteFreely application (1: Keys, 2: Add New Access Key)

Select OIDC/OpenID as the key type and click Create. Monosign generates the Client Id and Client Secret automatically.

image-20261014-085549.png
Creating the OIDC/OpenID Access Key (1: Type OIDC/OpenID, 2: Create)

Property

Value

Options

Type

OIDC/OpenID

Rest API, OAuth 2.0, JWT, OIDC/OpenID, SAML, RADIUS, Access Gateway, LDAP, AuthN/Z Server

Client Id / Client Secret

Generated automatically

Use the eye icon next to the secret to reveal it. Both values are required in step 4.

Session

System Default

System Default, On-demand, Permanent

State

Enabled

Enabled, Disabled

Never Expires

Yes

Turn off to define a specific expiration date for the key.

Configuration details for the WriteFreely application are provided as follows:

image-20261014-171512.png
OIDC/OpenID Access Key Details

Monosign value

Example

Used in WriteFreely as

Client Id

<client-id>

client_id

Client Secret

<client-secret>

client_secret

Auth Url

https://<monosign-host>/openid/authorize

host + auth_endpoint (/openid/authorize)

Access Token Url

https://<monosign-host>/openid/token

host + token_endpoint (/openid/token)

User Info Url

https://<monosign-host>/openid/userinfo

host + inspect_endpoint (/openid/userinfo)

2- Configuring the OIDC/OpenID Settings on Monosign

Click the Configure button of the OpenID Connect (OIDC) key to open the OIDC/OpenID settings and add the callback address of WriteFreely to Allowed Redirect URIs.

image-20261014-171757.png
OIDC/OpenID Settings (Allowed Redirect URIs)

Property

Value

Description

Allowed Redirect URIs

https://<writefreely-address>/oauth/callback/generic

The address where Monosign sends the user back after sign-in. The path /oauth/callback/generic is fixed by WriteFreely for the generic provider. Use the public (HTTPS) address of WriteFreely; the host name must be the same as the host value in the [app] section of its configuration.

Signing Key / Key Id / Password, Issuer, Audience, Scope, Resource

Empty

Optional custom JWT settings. They are not needed. WriteFreely sends the scopes itself.

Token lifetimes, CORS

Empty

Default values are used.

WriteFreely takes the user name from the claim preferred_username. Monosign does not return this claim by default, so open the Claim Mapping tab of the key, add the following mapping and click Update.

Claim

Value

Description

preferred_username

{{UserName}}

The Monosign user name. WriteFreely uses it as the user name and for the address of the blog. The claims sub (user identifier), name (display name) and email are returned by Monosign by default.

3- Assign a User to the WriteFreely Application

Please follow the below instructions on how to assign a user to the WriteFreely application. Open the application, click the Assignments tab and click Assign a User.

image-20261014-085716.png
Assignments tab of the WriteFreely application (1: Assignments, 2: Assign a User)

Search and select the users who can sign in to WriteFreely, check the Expiration Date and save. You can select more than one user.

image-20261014-085744.png
Assign a User dialog (select the users, set the Expiration Date)

Property

Value

Description

User(s)

Selected users

Users who can sign in to WriteFreely with Monosign.

Expiration Date

Default one year

The assignment expires on this date.

4- Configuration Single Sign-On for WriteFreely

As we mentioned at the start, please check out the WriteFreely documentation first. WriteFreely is configured with the config.ini file (in the Docker deployment it is in the /data folder). Add the following section to the file and replace the placeholder values.

[oauth.generic]
client_id          = <client-id>
client_secret      = <client-secret>
host               = https://<monosign-host>
display_name       = Monosign
auth_endpoint      = /openid/authorize
token_endpoint     = /openid/token
inspect_endpoint   = /openid/userinfo
scope              = openid profile email
map_user_id        = sub
map_username       = preferred_username
map_display_name   = name
map_email          = email
allow_disconnect   = false

Option

Value

Description

client_id / client_secret

Client Id / Client Secret

Copied from the Monosign OIDC/OpenID Access Key Details created in the first step.

host

https://<monosign-host>

Address of Monosign. WriteFreely appends the three endpoint paths to it.

auth_endpoint / token_endpoint / inspect_endpoint

/openid/authorize, /openid/token, /openid/userinfo

Authorization, token and UserInfo endpoint of Monosign. WriteFreely does not read the discovery document, so the paths must be written.

scope

openid profile email

Requested scopes, separated by space.

map_user_id

sub

Field of the UserInfo response that identifies the user. WriteFreely links the account with this value, so it must not change and must not be empty.

map_username / map_display_name / map_email

preferred_username / name / email

Fields that fill the “Finish creating account” form at the first sign-in. preferred_username needs the claim mapping of step 2.

display_name

Monosign

Text of the button on the sign-in page (“Sign in with Monosign”).

allow_disconnect

false

Users cannot remove the link between their account and Monosign.

auth_use_basic_auth

Not set

Optional (v0.17.2 and newer). By default WriteFreely sends the client credentials only in the HTTP Basic header, which Monosign accepts. Set it to true to send them in the request body instead; Monosign accepts this too.

New users can create an account at the first sign-in only when registration is open: open_registration = true in the [app] section. When it is false, a Monosign user without a WriteFreely account cannot sign in. The host value of the [app] section must be the public HTTPS address of WriteFreely.

The configuration file contains the client secret. Restrict its permissions (for example chmod 600) and do not store it in a shared repository.

For reference, the Docker deployment that was used for this document is below. The container runs as a non-root user and the data folder must be writable by this user.

YAML
services:
  writefreely:
    image: ghcr.io/writefreely/writefreely:latest
    container_name: writefreely
    command: ["-c", "/data/config.ini", "serve"]
    ports:
      - "6277:8080"
    volumes:
      - ./data:/data
      - ./keys:/go/keys
    cap_drop:
      - ALL
    security_opt:
      - no-new-privileges:true
    restart: unless-stopped

Recreate the container so that the new configuration is loaded:

Bash
cd <writefreely-compose-directory>
docker compose up -d --force-recreate

The sign-in page must now show the Sign in with Monosign button.

5- Sign In Test

Now try to log in to WriteFreely using Monosign SSO.

  1. Open a new browser window (or a private window) and type the WriteFreely address. On the sign-in page click Sign in with Monosign.

image-20261014-171707.png
WriteFreely sign-in page with the “Sign in with Monosign” button
  1. WriteFreely redirects the browser to the Monosign sign-in page of the WriteFreely application. You can log in passwordless with your QR code (Monofor Identity), with a Passkey or with your user name and password (Sign in with Password). If you are already signed in to Monosign, the page is skipped.

  2. After the sign-in Monosign redirects the browser back to WriteFreely (/oauth/callback/generic). At the first sign-in WriteFreely opens the Finish creating account page. The display name, the user name and the e-mail address are filled in from the Monosign claims. Check them (the user name is also used for the address of the blog) and click Next to create the account. The next sign-ins go directly to the WriteFreely account.

    image-20261015-083830.png

The sign-in of WriteFreely is started with a simple address (/oauth/generic), so Monosign can start it directly. If you enter https://<writefreely-address>/oauth/generic as the Url of the application (step 1), the user who opens WriteFreely from the Monosign portal is redirected to the Monosign sign-in without clicking the button (IdP-initiated sign-in).

Troubleshooting

Symptom

Cause

Solution

After the sign-in at Monosign, WriteFreely shows {"error":"unable to exchange code for access token"}. The Monosign log contains Multiple client credentials cannot be specified

The WriteFreely version is older than v0.17.2 (for example v0.17.1). It sends the client credentials twice, which is against RFC 6749 section 2.3.

Upgrade to WriteFreely v0.17.2 or a newer build (for example the image tag latest). Back up the data and keys folders before the upgrade.

The Sign in with Monosign button is not shown

The [oauth.generic] section is missing or incomplete, or the container was not recreated.

Check the config.ini (step 4) and run docker compose up -d --force-recreate.

Monosign shows a redirect URI error

The redirect URI that WriteFreely sends does not exactly match the Allowed Redirect URIs.

Add https://<writefreely-address>/oauth/callback/generic in Monosign (step 2). The host name must be the same as the host value of the [app] section.

The user name on the “Finish creating account” page is empty

The claim preferred_username is not returned by Monosign.

Add the mapping preferred_username={{UserName}} on the Claim Mapping tab of the key and click Update (step 2).

A new Monosign user cannot sign in

Registration is closed (open_registration = false) or the user is not assigned in Monosign.

Set open_registration = true in the [app] section, or create the user first. Assign the user in Monosign (step 3).

WriteFreely refuses the user name on the account form

The Monosign user name is not accepted as a WriteFreely user name.

Change the user name on the form before you click Next.

WriteFreely cannot reach Monosign (certificate or network error in the log)

The container cannot resolve or trust the address of Monosign.

Check DNS and firewall rules of the WriteFreely host and that the certificate of Monosign is issued by a trusted CA.

ID token validation, SAML or OIDC discovery is required

WriteFreely supports OAuth 2.0 only.

Use the OAuth 2.0 integration in this document.

After completing the configuration on WriteFreely and Monosign, it is better to test in a new private browser window if the SSO doesn’t work, because old session cookies of the WriteFreely address may cause errors.