Skip to content

Set up or change the identity provider

PUT
/org/sso/provider
curl --request PUT \
--url https://api.asklucy.eu/v1/org/sso/provider \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "kind": "entra", "name": "example", "client_id": "example", "client_secret": "example", "tenant_id": "example", "issuer": "https://example.com" }'

One provider per organization. The admin registers Lucy at their provider (redirect URI redirect_uri, scopes openid profile email; for Entra, a web app registration in their tenant with the Microsoft Graph User.Read permission) and pastes the client ID and secret here. The secret goes to the identity service in this call and is never kept, returned or logged by Lucy. Accounts are made on first sign-in and matched to existing ones by verified email.

The same kind again updates the provider: a new client_secret replaces the old one, none keeps it. A change of provider (kind, client_id, tenant_id or issuer) undoes the last test and stops enforcing. Audited as org.sso.provider_set (never the secret).

Media typeapplication/json
object
kind
required

Microsoft Entra ID, Google Workspace, or any OpenID Connect provider (Okta, Keycloak, Authentik…).

string
Allowed values: entra google oidc
name

Optional; the kind’s name when absent.

string
<= 60 characters
client_id
required
string
<= 200 characters
client_secret

Required for a new provider; on an update, absent keeps the one the identity service has.

string
<= 1000 characters
tenant_id

Entra only; the directory (tenant) ID, a GUID. Absent: any work or school account.

string
issuer

oidc only: the issuer URL, whose /.well-known/openid-configuration says the rest.

string format: uri

OK

Media typeapplication/json
object
redirect_uri
required

What to register at the provider as the redirect (reply) URI.

string format: uri
provider
required
One of:
object
kind
required

Microsoft Entra ID, Google Workspace, or any OpenID Connect provider (Okta, Keycloak, Authentik…).

string
Allowed values: entra google oidc
name
required

Shown on the sign-in page and in Lucy.

string
client_id
required
string
tenant_id
required

Entra; null means any work or school account.

string | null
issuer
required

The OpenID Connect issuer (oidc only).

string | null
test
required
One of:
object
status
required
string
Allowed values: passed failed
at
required
string format: date-time
email
required

The account that signed in, when the provider said.

string | null
error
required

Why it failed, in a sentence.

string | null
updated_at
required
string | null format: date-time
updated_by
required
One of:
object
id
required

Zitadel user ID.

string
name
required
string
email
string | null format: email
kind

service is a customer system’s Zitadel service user; agent is a service agent (its ID is the agt_ ID), the author of its runs’ messages.

string
Allowed values: person service agent
domains
required
Array<object>
object
domain
required
string
verified
required
boolean
dns
required
One of:
object
type
required
string
name
required
string
value
required
string
enforce
required

Members sign in only through the provider.

boolean
can_enforce
required

A provider, a verified domain and a passed test sign-in.

boolean

Example

{
"redirect_uri": "https://id.asklucy.eu/idps/callback",
"provider": {
"kind": "entra",
"test": {
"status": "passed"
},
"updated_by": {
"kind": "person"
}
},
"domains": [
{
"domain": "acme.lu",
"dns": {
"type": "TXT",
"name": "_asklucy-challenge.acme.lu",
"value": "asklucy-domain-verification=4f1c0e9b2a7d4c6e8b1f3a5d7c9e0b2d"
}
}
]
}

The request is invalid; errors lists what’s wrong.

Media typeapplication/problem+json

RFC 9457 problem details.

object
type
required
string format: uri-reference
title
required
string
status
required
integer
detail
string
instance
string
request_id
string
quota

For quota-exceeded, the window that is used up.

object
window
required
string
Allowed values: five_hours week month
percent_used
required
number
<= 100
resets_at
required

Null for a rolling window that hasn’t started.

string | null format: date-time
limited_by
required

organization when the organization’s budget is closer to running out than the member’s own limit.

string
Allowed values: personal organization
request
One of:

A request as its member sees it, where they asked.

object
id
required
string
status
required
string
Allowed values: pending approved declined withdrawn
created_at
required
string format: date-time
decided_at
required
string | null format: date-time
note
required

What the admin who decided wrote back.

string | null
errors

Field-level problems (400 only).

Array<object>
object
field
required

JSON pointer into the request body.

string
message
required
string

Example

{
"type": "https://docs.asklucy.eu/errors/answer-in-progress",
"quota": {
"window": "five_hours",
"limited_by": "personal",
"request": {
"status": "pending"
}
}
}
X-Request-Id
string

Unique per request; quote it to support.

Missing, expired or invalid token.

Media typeapplication/problem+json

RFC 9457 problem details.

object
type
required
string format: uri-reference
title
required
string
status
required
integer
detail
string
instance
string
request_id
string
quota

For quota-exceeded, the window that is used up.

object
window
required
string
Allowed values: five_hours week month
percent_used
required
number
<= 100
resets_at
required

Null for a rolling window that hasn’t started.

string | null format: date-time
limited_by
required

organization when the organization’s budget is closer to running out than the member’s own limit.

string
Allowed values: personal organization
request
One of:

A request as its member sees it, where they asked.

object
id
required
string
status
required
string
Allowed values: pending approved declined withdrawn
created_at
required
string format: date-time
decided_at
required
string | null format: date-time
note
required

What the admin who decided wrote back.

string | null
errors

Field-level problems (400 only).

Array<object>
object
field
required

JSON pointer into the request body.

string
message
required
string

Example

{
"type": "https://docs.asklucy.eu/errors/answer-in-progress",
"quota": {
"window": "five_hours",
"limited_by": "personal",
"request": {
"status": "pending"
}
}
}
X-Request-Id
string

Unique per request; quote it to support.

The token is valid but lacks the role this needs.

Media typeapplication/problem+json

RFC 9457 problem details.

object
type
required
string format: uri-reference
title
required
string
status
required
integer
detail
string
instance
string
request_id
string
quota

For quota-exceeded, the window that is used up.

object
window
required
string
Allowed values: five_hours week month
percent_used
required
number
<= 100
resets_at
required

Null for a rolling window that hasn’t started.

string | null format: date-time
limited_by
required

organization when the organization’s budget is closer to running out than the member’s own limit.

string
Allowed values: personal organization
request
One of:

A request as its member sees it, where they asked.

object
id
required
string
status
required
string
Allowed values: pending approved declined withdrawn
created_at
required
string format: date-time
decided_at
required
string | null format: date-time
note
required

What the admin who decided wrote back.

string | null
errors

Field-level problems (400 only).

Array<object>
object
field
required

JSON pointer into the request body.

string
message
required
string

Example

{
"type": "https://docs.asklucy.eu/errors/answer-in-progress",
"quota": {
"window": "five_hours",
"limited_by": "personal",
"request": {
"status": "pending"
}
}
}
X-Request-Id
string

Unique per request; quote it to support.

Another service Lucy needed didn’t answer as it should (the problem’s type says which).

Media typeapplication/problem+json

RFC 9457 problem details.

object
type
required
string format: uri-reference
title
required
string
status
required
integer
detail
string
instance
string
request_id
string
quota

For quota-exceeded, the window that is used up.

object
window
required
string
Allowed values: five_hours week month
percent_used
required
number
<= 100
resets_at
required

Null for a rolling window that hasn’t started.

string | null format: date-time
limited_by
required

organization when the organization’s budget is closer to running out than the member’s own limit.

string
Allowed values: personal organization
request
One of:

A request as its member sees it, where they asked.

object
id
required
string
status
required
string
Allowed values: pending approved declined withdrawn
created_at
required
string format: date-time
decided_at
required
string | null format: date-time
note
required

What the admin who decided wrote back.

string | null
errors

Field-level problems (400 only).

Array<object>
object
field
required

JSON pointer into the request body.

string
message
required
string

Example

{
"type": "https://docs.asklucy.eu/errors/answer-in-progress",
"quota": {
"window": "five_hours",
"limited_by": "personal",
"request": {
"status": "pending"
}
}
}
X-Request-Id
string

Unique per request; quote it to support.

Storage for this isn’t configured on the server (e.g. …/errors/desktop-unavailable).

Media typeapplication/problem+json

RFC 9457 problem details.

object
type
required
string format: uri-reference
title
required
string
status
required
integer
detail
string
instance
string
request_id
string
quota

For quota-exceeded, the window that is used up.

object
window
required
string
Allowed values: five_hours week month
percent_used
required
number
<= 100
resets_at
required

Null for a rolling window that hasn’t started.

string | null format: date-time
limited_by
required

organization when the organization’s budget is closer to running out than the member’s own limit.

string
Allowed values: personal organization
request
One of:

A request as its member sees it, where they asked.

object
id
required
string
status
required
string
Allowed values: pending approved declined withdrawn
created_at
required
string format: date-time
decided_at
required
string | null format: date-time
note
required

What the admin who decided wrote back.

string | null
errors

Field-level problems (400 only).

Array<object>
object
field
required

JSON pointer into the request body.

string
message
required
string

Example

{
"type": "https://docs.asklucy.eu/errors/answer-in-progress",
"quota": {
"window": "five_hours",
"limited_by": "personal",
"request": {
"status": "pending"
}
}
}
X-Request-Id
string

Unique per request; quote it to support.