Authentication
View .mdEmail sign-in, token verification, and IndieAuth endpoints.
https://micro.blog
/account/signin
Emails a sign-in link to an existing account. When app_name and redirect_url match a registered app, the link opens redirect_url with a temporary token appended, such as epilogue://signin/ABCDEF1234567890ABCD. Exchange that token with POST /account/verify within 15 minutes. No authentication is required.
app_name and redirect_url. Email help@micro.blog with the app name and redirect URL to request registration.
Example Request
curl -X POST "https://micro.blog/account/signin?email=example%40example.com&app_name=Example+App&redirect_url=exampleapp%3A%2F%2Fsignin%2F"
Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
email
|
string | Required |
Email address for the account.
Example:
example@example.com
|
app_name
|
string | Optional |
Name of the registered app requesting access. Without it, the email links to a sign-in on the Micro.blog website instead of your app.
Example:
Example App
|
redirect_url
|
string | Optional |
Registered redirect URL for the app. Required when app_name is set, and the pair must match a registered app. The temporary token is appended to the end of this URL.
Example:
exampleapp://signin/
|
Response
200 OK application/json
Returns an empty JSON object when the email is sent. Errors also return 200 with an error message, for example {"error": "Email address not found."} or {"error": "App name and redirect URL must be registered."}.
Example Response
{}
/account/verify
Exchanges the temporary token from the sign-in email for a permanent app token, or checks an existing app token, and returns account information. Send the token as a parameter, not in an Authorization header. Always store the returned token, because it can differ from the one you sent. Temporary tokens are exchanged for a permanent one, and tokens close to expiry are renewed.
Example Request
curl -X POST "https://micro.blog/account/verify?token=ABCDEF1234567890ABCD"
Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
token
|
string | Required |
The temporary token from the sign-in redirect, or an existing app token. Pass the bare token value, without a Bearer prefix.
Example:
ABCDEF1234567890ABCD
|
Response Properties
token
string
Bearer Token
Authorization: Bearer {token} on authenticated requests.
Authorization header as Bearer {token} for authenticated API requests.
ABCDEF1234567890ABCD
name
string
full_name.
Manton Reece
username
string
manton
avatar
string
https://avatars.micro.blog/avatars/2026/1.jpg
bio
string
default_site
string
manton.micro.blog
full_name
string
Manton Reece
gravatar_url
string
avatar.
https://avatars.micro.blog/avatars/2026/1.jpg
has_site
boolean
true
has_inkwell
boolean
true
plan
string
premium
plans
array of string
[premium]
is_fullaccess
boolean
true. Kept for older clients.
true
is_premium
boolean
true
is_using_ai
boolean
Response
200 OK application/json
Returns the API token and account information. An unknown or expired token also returns 200, with {"error": "App token was not valid."}.
Example Response
{
"token": "ABCDEF1234567890ABCD",
"name": "Manton Reece",
"username": "manton",
"avatar": "https://avatars.micro.blog/avatars/2026/1.jpg",
"bio": "",
"default_site": "manton.micro.blog",
"full_name": "Manton Reece",
"gravatar_url": "https://avatars.micro.blog/avatars/2026/1.jpg",
"has_site": true,
"has_inkwell": true,
"plan": "premium",
"plans": [
"premium"
],
"is_fullaccess": true,
"is_premium": true,
"is_using_ai": false
}
/indieauth/auth
IndieAuth authorization endpoint. Send the user’s browser here to approve your app. The user signs in on the Micro.blog website if needed, sees an authorization screen, and on approval is redirected to redirect_uri with code and state query parameters. The code is valid for 60 seconds and can be used once. Exchange it with POST /indieauth/token, or with POST /indieauth/auth if you only need the user’s identity. Open this URL in a browser, not with an API token. Requests that send an Authorization header get a 403.
redirect_uri must have the same scheme, host, and port as client_id, unless the client metadata at client_id lists it. A JSON document with redirect_uris, or <link rel="redirect_uri"> tags in an HTML page, both work. Apps with a custom URL scheme must publish client metadata. The JSON metadata can also set client_name and logo_uri for the authorization screen.
Example Request
curl -X GET "https://micro.blog/indieauth/auth?client_id=https%3A%2F%2Fexample-app.com%2F&redirect_uri=https%3A%2F%2Fexample-app.com%2Fcallback&state=state123&response_type=code&scope=profile+create+media&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256"
Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
client_id
|
string | Required |
Your app’s client ID, an http or https URL. Micro.blog fetches it for the app name, logo, and allowed redirect URLs.
Example:
https://example-app.com/
|
redirect_uri
|
string | Required |
URL to send the user back to after approval. See the note above for which URLs are accepted.
Example:
https://example-app.com/callback
|
me
|
string | Optional |
The user’s blog URL. Defaults to the user’s hosted Micro.blog blog.
Example:
https://example.micro.blog/
|
state
|
string | Optional |
Opaque value returned unchanged to redirect_uri. Use it to protect against CSRF.
Example:
state123
|
response_type
|
string | Optional |
IndieAuth response type. Send code.
Example:
code
|
scope
|
string | Optional |
Space-separated scopes to request. Supported scopes are profile, read, write, create, update, delete, media, follow, and channels. Others are ignored. write includes read, create, update, delete, and media.
Example:
profile create media
|
code_challenge
|
string | Optional |
PKCE code challenge, the 43-character base64url SHA-256 hash of your code verifier. When set, the token exchange must send the matching code_verifier.
Example:
E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
|
code_challenge_method
|
string | Optional |
PKCE method. Must be S256 when code_challenge is set.
Example:
S256
|
Response
200 OK text/html
Returns the authorization screen. Users who aren’t signed in are redirected to the sign-in page first. An invalid PKCE challenge or a redirect_uri that isn’t allowed returns a 400 error page.
Example Response
<!doctype html>
<html>
<body>IndieAuth authorization screen</body>
</html>
/indieauth/auth
Verifies an IndieAuth authorization code and returns the user’s identity, without issuing an access token. Use it when your app only needs to know who signed in. No authentication is required.
Example Request
curl -X POST "https://micro.blog/indieauth/auth?code=AUTHCODE&client_id=https%3A%2F%2Fexample-app.com%2F&redirect_uri=https%3A%2F%2Fexample-app.com%2Fcallback&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
code
|
string | Required |
Authorization code from the redirect.
Example:
AUTHCODE
|
client_id
|
string | Required |
The same client_id sent to GET /indieauth/auth.
Example:
https://example-app.com/
|
redirect_uri
|
string | Required |
The same redirect_uri sent to GET /indieauth/auth.
Example:
https://example-app.com/callback
|
code_verifier
|
string | Optional |
PKCE code verifier, 43 to 128 characters. Required when the authorization request included code_challenge.
Example:
dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
|
Response
200 OK application/json
Returns the user’s blog URL and profile. An invalid, expired, or already used code, or a mismatched client_id, redirect_uri, or code_verifier, returns 400 with {"error": "invalid_grant", "error_description": "..."}.
Example Response
{
"me": "https://manton.micro.blog/",
"profile": {
"name": "Manton Reece",
"url": "https://manton.micro.blog/",
"photo": "https://avatars.micro.blog/avatars/2026/1.jpg",
"nickname": "manton"
}
}
/indieauth/token
Returns the blog URL, app name, scopes, and profile for an access token. Use it to check a token you already have.
Example Request
curl -X GET "https://micro.blog/indieauth/token" \
--header "Authorization: Bearer ABCDEF1234567890ABCD"
Header Parameters
| Name | Type | Required | Description |
|---|---|---|---|
Authorization
|
string | Required |
Bearer token for authentication. Format: Bearer {token}.
|
Response
200 OK application/json
Returns token information. client_id is the name of the app the token was issued to, and scope is a space-separated list. An unknown or expired token returns 400 with the plain-text message Token or user not found.
Example Response
{
"me": "https://manton.micro.blog/",
"client_id": "Example App",
"scope": "profile create media",
"profile": {
"name": "Manton Reece",
"url": "https://manton.micro.blog/",
"photo": "https://avatars.micro.blog/avatars/2026/1.jpg",
"nickname": "manton"
}
}
/indieauth/token
Exchanges an IndieAuth authorization code for an access token and the user’s profile. No authentication is required.
Example Request
curl -X POST "https://micro.blog/indieauth/token?code=AUTHCODE&client_id=https%3A%2F%2Fexample-app.com%2F&redirect_uri=https%3A%2F%2Fexample-app.com%2Fcallback&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
code
|
string | Required |
Authorization code from the redirect.
Example:
AUTHCODE
|
client_id
|
string | Required |
The same client_id sent to GET /indieauth/auth.
Example:
https://example-app.com/
|
redirect_uri
|
string | Required |
The same redirect_uri sent to GET /indieauth/auth.
Example:
https://example-app.com/callback
|
code_verifier
|
string | Optional |
PKCE code verifier, 43 to 128 characters. Required when the authorization request included code_challenge.
Example:
dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
|
Response
200 OK application/json
Returns the granted scopes and profile. token_type and access_token are included only when the user granted a scope other than profile. An invalid, expired, or already used code, or a mismatched client_id, redirect_uri, or code_verifier, returns 400 with {"error": "invalid_grant", "error_description": "..."}.
Example Response
{
"scope": "profile create media",
"me": "https://manton.micro.blog/",
"profile": {
"name": "Manton Reece",
"url": "https://manton.micro.blog/",
"photo": "https://avatars.micro.blog/avatars/2026/1.jpg",
"nickname": "manton"
},
"token_type": "Bearer",
"access_token": "ABCDEF1234567890ABCD"
}