Registering
All of this happens at id.costia.app/developer, with your own Costia account. There is no human review.
1. Create the partner
Section titled “1. Create the partner”The name you choose is what your customer sees on the consent screen, next to “wants to access your Costia account”. Use the one they know you by: it is the only thing they have to go on when deciding whether to authorise you.
You can register up to ten partners per account.
2. Verify your domain
Section titled “2. Verify your domain”Only if you are going to write invoices. Signing in does not need it.
When you claim a domain you get a token, and you publish it one of two ways:
_costia-challenge.yourshop.com TXT costia-verify-xxxxxxxxxxxxhttps://yourshop.com/.well-known/costia-partnerThe file’s content is the token, verbatim. Then you press verify.
Either one is enough. The check runs over HTTPS only, does not follow redirects and rejects private addresses — so a domain pointing at your internal network does not count as proof.
Once verified, your brand is pinned to what you proved, not to what you typed. That
is what unlocks invoices:write.
On the consent screen, Costia shows every actual redirect domain used by the client. It gets a Verified badge only when it matches a domain you proved or one of its subdomains; every other domain gets an Unverified badge. Proving one domain does not lend trust to a redirect URL hosted somewhere else.
3. Create the OAuth client
Section titled “3. Create the OAuth client”You need two things.
The client name, which is what people read on the consent screen.
The redirect URLs, which your framework decides, not you. With
Better Auth it is https://your-domain/api/auth/callback/costia;
with NextAuth, /api/auth/callback/costia; with Spring Security,
/login/oauth2/code/costia. They must match character for character, with no wildcards or
fragments. Server clients use https. A public native application may also use a
reverse-domain private scheme such as com.yourshop.app:/oauth2redirect. If it does not
match, authorization is rejected before it starts: this stops a third party receiving the
code in your name.
Choose confidential when the client runs on a server that can protect credentials. You
receive a client_id and client_secret. Choose public for an installed application:
it receives only a client_id and authenticates with PKCE, because a secret embedded in a
binary can be extracted and is not a secret.
A public client cannot request invoices:write: anybody can imitate its client_id, so
Costia cannot let it write invoices under a verified brand. It also receives no refresh
token and cannot request offline_access; it repeats authorization when access is needed
again. Client type is immutable after creation: create a new client to migrate between
public and confidential.
You can list every client_id, edit the name, scopes and multiple exact login redirect
URLs, add post-logout redirect URLs, rotate the secret, or delete the client. Costia’s
OIDC end-session endpoint is https://id.costia.app/connect/logout.
Which scopes to ask for
Section titled “Which scopes to ask for”Ask only for what you will use. Your customer can uncheck any of them except identification, and if they uncheck one they are told explicitly what your application will no longer be able to do.
| Scope | What for | Requirement |
|---|---|---|
openid |
Identify the account. Always present | — |
profile |
Read their name | — |
email |
Read their verified email | That exact address must be verified |
invoices:read |
Read their invoices | — |
invoices:write |
Write invoices in your name | Verified domain |
offline_access |
Keep working when they are not present | Confidential client only |
invoices:read and invoices:write are independent, not a ladder. A shop writes and
never reads; an accountant reads and never writes. Granting both is an explicit decision.
Asking for invoices:write without a verified domain is rejected when you create the
client, not when you use it — a client that never received the permission cannot ask
for it later.
Any enabled scope can be marked mandatory. It still starts unchecked: the person has to
grant it deliberately, but cannot continue without it. If email is mandatory and the
address is unverified, Costia asks them to sign in with Google or Apple using that exact
address, or send a single-use link when outbound email is configured for the environment.
The link expires, is delivery-rate-limited, and verifies only the exact address it was
sent to. Apple only counts when it actually supplies the email; one entered manually
afterwards is not verified.
Every authorization request must include all scopes you configured as mandatory; Costia
never silently expands the permissions requested by the client.
You can also suggest a default grant duration. The person can always change the date or choose no expiry. Once expired, the application has to ask again.
