Luna OAuth — API Reference

Base URL: https://oauth.luna99.it

Authentication backend: LDAP (dc=luna,dc=local) — Login format: uid@domain


Endpoints

GET|POST /oauth/validate     HTTP Basic Auth - validate credentials
GET      /oauth/authorize    OAuth2 Authorization Code - show login, return code
POST     /oauth/token        OAuth2 - exchange code or refresh token for tokens
GET      /oauth/userinfo     OAuth2 - get authenticated user profile
POST     /oauth/revoke       OAuth2 - revoke an access or refresh token
GET      /health             Health check (returns {"status":"ok"})

HTTP Basic Auth (simple validation)

For services that need direct credential validation without the OAuth redirect flow.

GET /oauth/validate
Authorization: Basic base64(uid@domain:password)

Response 200 (valid):
  {
    "sub":          "uid=john,ou=users,o=acme,ou=tenants,dc=luna,dc=local",
    "username":     "john",
    "email":        "john@acme.it",
    "name":         "John",
    "surname":      "Doe",
    "organization": "acme",
    "domain":       "acme.it",
    "services":     ["mail","sync","file"],
    "active":       true
  }

Response 401 (invalid):
  {"error": "invalid_credentials"}
  WWW-Authenticate: Basic realm="Luna OAuth"

Usage examples

# cURL
curl -u user@domain.it:password https://ooauth.luna99.it/oauth/validate

# Nginx auth_request
location /protected {
    auth_request /auth;
}
location = /auth {
    proxy_pass https://oauth.luna99.it/oauth/validate;
    proxy_set_header Authorization $http_authorization;
    proxy_pass_request_body off;
    proxy_set_header Content-Length "";
}

# Apache (mod_proxy + Basic Auth forwarding)
<Location /protected>
    AuthType Basic
    AuthName "Luna OAuth"
    AuthBasicProvider proxy
    AuthProxy https://oauth.luna99.it/oauth/validate
    Require valid-user
</Location>

# HAProxy
http-request set-header X-Auth-Header %[req.hdr(Authorization)]
http-request lua.auth_basic_check  # forward to /oauth/validate

# Perl (Mojo::UserAgent)
use MIME::Base64;
my $tx = $ua->get("https://oauth.luna99.it/oauth/validate" =>
    { Authorization => "Basic " . encode_base64("user:pass", "") });
if ($tx->res->code == 200) {
    my $user = $tx->res->json;  # { username, email, role, ... }
}

# Python (requests)
import requests
r = requests.get("https://oauth.luna99.it/oauth/validate",
                  auth=("username", "password"))
if r.status_code == 200:
    user = r.json()  # {"username": ..., "email": ..., "role": ...}

# Shell (wget)
wget -qO- --user=username --password=password     https://oauth.luna99.it/oauth/validate

OAuth 2.0 Authorization Code Flow

For web applications that need browser-based login with redirect.

Step 1 — Redirect user to authorize

GET /oauth/authorize
    ?response_type=code
    &client_id=YOUR_CLIENT_ID
    &redirect_uri=https://yourapp.example.com/callback
    &state=RANDOM_CSRF_STRING
    &scope=profile email

Parameters:
  response_type  required  Must be "code"
  client_id      required  Your registered client ID
  redirect_uri   required  Must match registered URI exactly
  state          required  Random string for CSRF protection
  scope          optional  Space-separated: profile, email

On success, user is redirected to:
  YOUR_REDIRECT_URI?code=AUTH_CODE&state=RANDOM_CSRF_STRING

Step 2 — Exchange code for tokens

POST /oauth/token
Content-Type: application/x-www-form-urlencoded

  grant_type=authorization_code
  &code=AUTH_CODE
  &redirect_uri=https://yourapp.example.com/callback
  &client_id=YOUR_CLIENT_ID
  &client_secret=YOUR_CLIENT_SECRET

Response 200:
  {
    "access_token":  "at-uuid",
    "refresh_token": "rt-uuid",
    "token_type":    "Bearer",
    "expires_in":    3600
  }

Error 400:  {"error": "invalid_grant"}
Error 401:  {"error": "invalid_client"}

Step 3 — Get user info

GET /oauth/userinfo
Authorization: Bearer ACCESS_TOKEN

Response 200:
  {
    "sub":          "uid=john,ou=users,o=acme,ou=tenants,dc=luna,dc=local",
    "username":     "john",
    "email":        "john@acme.it",
    "name":         "John",
    "surname":      "Doe",
    "organization": "acme",
    "domain":       "acme.it",
    "services":     ["mail","sync","file"],
    "active":       true
  }

Error 401:  {"error": "invalid_token"}

Refresh Token

POST /oauth/token
Content-Type: application/x-www-form-urlencoded

  grant_type=refresh_token
  &refresh_token=REFRESH_TOKEN
  &client_id=YOUR_CLIENT_ID
  &client_secret=YOUR_CLIENT_SECRET

Returns new access_token and refresh_token (same format as step 2).

Revoke Token

POST /oauth/revoke
Content-Type: application/x-www-form-urlencoded

  token=ACCESS_OR_REFRESH_TOKEN
  &token_type_hint=access_token    (or "refresh_token")

Always returns 200 {"status":"ok"}

Token Lifetimes

Authorization code   10 minutes   single use
Access token          1 hour
Refresh token        24 hours

Error Codes

invalid_credentials      Username or password wrong (Basic Auth)
missing_credentials      No Authorization header sent (Basic Auth)
invalid_client           Client ID or secret is wrong (OAuth)
invalid_grant            Auth code or refresh token invalid/expired/used (OAuth)
unsupported_grant_type   Only authorization_code and refresh_token supported
invalid_token            Access token is invalid, expired, or revoked

Registration

To register a new OAuth client, contact the administrator or use the admin panel.
HTTP Basic Auth requires no client registration — any active user can authenticate.

Plain-text API spec (for AI agents and scripts)