IAMApplication
Deployed and supported. The fields and commands described here are stable within version v1alpha1.
apiVersion | iam.stackngo.io/v1alpha1 |
kind | IAMApplication |
| Applied by | sng apply |
| Related commands | sng template gen IAMApplication, sng kind get IAMApplication, sng kind delete IAMApplication, sng iam app list · describe · credentials, sng tenant policy attach --app |
What it is for
An IAMApplication declares an OAuth2 / OIDC client for one of your applications: its redirect URLs, its flows (authorization_code, refresh_token, client_credentials…), its scopes, and the lifetime of its tokens. The platform creates the application and puts clientId, clientSecret, and issuer into a <nom>-oidc secret in your tenant, ready to be injected into an App. With directory: tenant, your applications' users (tenant directory) sign in at your tenant's issuer (https://auth.dev.stackngo.fr/t/acme), without a password.
Minimal example
apiVersion: iam.stackngo.io/v1alpha1
kind: IAMApplication
metadata:
name: billing-api
spec:
directory: tenant # your applications' users (default: platform)
displayName: Billing API
redirectURLs:
- https://billing-api.acme.dev.stackngo.app/auth/callback
grantTypes: [authorization_code, refresh_token]
scopes: [openid, profile, email]
sng apply billing-api.yml
sng kind get IAMApplication billing-api --json # status.credentials.secretName = billing-api-oidc
There is no equivalent imperative command: sng iam app lists and describes the directory's applications, but does not create them; the console offers an equivalent form.
Complete annotated example
apiVersion: iam.stackngo.io/v1alpha1
kind: IAMApplication
metadata:
name: portal # object name; the name in the SSO derives from it (sng-…-app-portal)
spec:
displayName: Portail client # shown on the sign-in screen, 256 characters max
homeURL: https://portal-web.acme.dev.stackngo.app # HTTPS, no local or private address
redirectURLs: # 32 max; HTTPS, except http://127.0.0.1 and http://localhost
- https://portal-web.acme.dev.stackngo.app/auth/callback
- http://127.0.0.1:*/callback # native application or CLI (any port)
grantTypes: # 16 max
- authorization_code
- refresh_token
scopes: [openid, profile, email] # 32 max
credentialsSecret:
name: portal-oidc # default: <nom>-oidc
create: true # false: no Secret, credentials in the SSO only
token:
expireInHours: 1 # access token: 1 to 8760 h; 168 if spec.token is omitted
refreshExpireInHours: 720 # refresh token: 168 by default with refresh_token
deletionPolicy: Delete # Block (default), Orphan, or Delete: see "What happens when you delete"
The Secret produced:
| Key | Content |
|---|---|
clientId | OAuth2 client identifier |
clientSecret | client secret |
issuer | URL of the OIDC issuer (https://auth.dev.stackngo.fr/t/acme for directory: tenant); discovery at <issuer>/.well-known/openid-configuration |
Fields
Cross-field validation rules
The schema has no CEL rule. sng apply checks the types, lengths, and bounds in the table below (for example token.expireInHours: 0 is rejected, minimum 1). The following rules are checked by the platform after sng apply, when the manifest is applied:
redirectURLs: each URL over HTTPS, neither a local address, nor a private address, nor a metadata address; exception forhttp://127.0.0.1andhttp://localhost(native applications and CLIs), including with a wildcard porthttp://127.0.0.1:*/callback.homeURL: HTTPS, same prohibitions, without the local exception.credentialsSecret.name: DNS name (lowercase, digits,-,.) or empty.token.expireInHours: at least 1 whenspec.tokenis present.token.refreshExpireInHours: 0is forbidden whengrantTypescontainsrefresh_token.assignableRolesis not supported yet: a non-empty list is refused (assignableRoles: field not supported yet, it would have no effect; remove it). Remove the field, or leave it empty.
An application rejected at this stage stays Ready: False with the reason UnsupportedConfiguration and the rule's message.
IAMApplication
| Champ | Description | Défaut | Validation |
|---|---|---|---|
apiVersion string | iam.stackngo.io/v1alpha1 | ||
kind string | IAMApplication | ||
metadata ObjectMeta | Seul metadata.name est à renseigner (nom de la ressource dans votre tenant). | ||
spec IAMApplicationSpec | |||
status IAMApplicationStatus |
IAMApplicationSpec
| Champ | Description | Défaut | Validation |
|---|---|---|---|
displayName string | Nom affiché sur l'écran de connexion de l'application (256 caractères au plus). | MaxLength: 256 | |
homeURL string | Adresse d'accueil de l'application, en HTTPS. Les adresses locales et privées sont refusées. | MaxLength: 2048 | |
redirectURLs string array | Adresses vers lesquelles l'utilisateur est renvoyé après connexion (32 au plus). HTTPS obligatoire, sauf http://127.0.0.1 et http://localhost pour les applications natives et les CLI. | MaxItems: 32 | |
postLogoutRedirectURLs string array | Adresses de retour admises après une déconnexion (post_logout_redirect_uri d'OIDC RP-Initiated Logout), mêmes règles que redirectURLs. Backend auth seulement : sans elles, /end_session refuse la redirection et la session du navigateur reste ouverte. | MaxItems: 32 Optional: {} | |
grantTypes string array | Flux OAuth2 autorisés (16 au plus), par exemple authorization_code, refresh_token ou client_credentials. | MaxItems: 16 | |
scopes string array | Périmètres de données que l'application peut demander (32 au plus), par exemple openid, profile, email. | MaxItems: 32 | |
assignableRoles string array | Pas encore pris en charge : une liste non vide est refusée. Laissez ce champ vide. | MaxItems: 64 | |
credentialsSecret CredentialsSecretSpec | Où déposer les identifiants de l'application (clientId, clientSecret, issuer) pour les injecter dans une App. | Optional: {} | |
token TokenPolicy | Durées de vie des jetons émis. Facultatif : sans ce bloc, les jetons d'accès durent 168 heures (7 jours). | Optional: {} | |
public boolean | Client public (CLI, application native) : PKCE obligatoire, aucun secret utilisé, redirections loopback admises. | Optional: {} | |
clientID string | Identifiant OAuth fixé (ex. compilé dans un binaire) au lieu d'un identifiant généré. Jamais au format UUID. | Pattern: ^[A-Za-z0-9._-]\{8,128\}$ Optional: {} | |
directory string | Utilisateurs que l'application connecte : platform (défaut, membres de votre tenant sur StackNGO) ou tenant (utilisateurs de vos applications, émetteur propre à votre tenant). Ne change plus après la création : en créer une autre. Incompatible avec le scope urn:stackngo:introspect. | platform | Enum: [platform tenant] Optional: {} |
deletionPolicy DeletionPolicy | Sort de l'application quand le manifeste est supprimé : Block (défaut), Orphan ou Delete. | Block | Enum: [Block Orphan Delete] |
IAMApplicationStatus
| Champ | Description | Défaut | Validation |
|---|---|---|---|
observedGeneration integer | Dernière version du manifeste (metadata.generation) prise en compte par la plateforme. | ||
provider ProviderStatus | Identité de la ressource dans le service d'authentification. | ||
lastSyncedAt Time | Date de la dernière prise en compte réussie du manifeste. | Optional: {} | |
conditions Condition array | Conditions décrivant l'état actuel de la ressource (Ready…). | ||
credentials CredentialsStatus | État du secret des identifiants OIDC, sans les valeurs secrètes. | ||
oauthSecretRef SecretReference | Deprecated: use status.credentials.secretName. | ||
machineOrigin string | Tenant auquel sont rattachées les sessions ouvertes avec les identifiants de cette application, quand c'est une application machine. Vide sinon. |
CredentialsSecretSpec
CredentialsSecretSpec configure le secret qui reçoit les identifiants OIDC de l'application.
| Champ | Description | Défaut | Validation |
|---|---|---|---|
name string | Nom du secret qui reçoit les identifiants (clientId, clientSecret, issuer). Défaut : <nom-de-l-application>-oidc. Ignoré quand create vaut false. | MaxLength: 253 Pattern: ^(|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)$ Optional: {} | |
create boolean | À false, aucun secret n'est créé dans votre tenant : les identifiants ne sont conservés que par le service d'authentification (cas typique d'une application machine à machine). Défaut : true. | true | Optional: {} |
TokenPolicy
TokenPolicy fixe la durée de vie des jetons émis pour l'application.
| Champ | Description | Défaut | Validation |
|---|---|---|---|
expireInHours integer | Durée de vie du jeton d'accès, en heures. 0 est refusé. Défaut : 168. | 168 | Maximum: 8760 Minimum: 1 Optional: {} |
refreshExpireInHours integer | Durée de vie du jeton de rafraîchissement, en heures. Non renseigné : 168 si grantTypes contient refresh_token, 0 sinon. La valeur 0 n'est acceptée que sans le grant refresh_token. | Maximum: 8760 Minimum: 0 Optional: {} |
DeletionPolicy
Type sous-jacent : string
DeletionPolicy indique ce que devient la ressource quand vous supprimez son manifeste : Block bloque la suppression tant que la ressource est encore utilisée, Orphan la conserve, Delete la supprime.
Règles de validation :
Enum: [Block Orphan Delete]
| Valeur | Description |
|---|---|
Block | Bloque la suppression tant que la ressource est encore utilisée par une autre. |
Orphan | Supprime le manifeste mais conserve la ressource créée. |
Delete | Supprime la ressource avec le manifeste, sans vérifier son usage. |
ProviderStatus
ProviderStatus identifie la ressource dans le service d'authentification.
| Champ | Description | Défaut | Validation |
|---|---|---|---|
owner string | Organisation propriétaire de l'objet dans l'annuaire d'identité. Renseigné par la plateforme. | ||
name string | Nom de l'objet dans l'annuaire d'identité. Renseigné par la plateforme. | ||
resourceID string | Identifiant de l'objet dans l'annuaire d'identité. Renseigné par la plateforme. |
CredentialsStatus
CredentialsStatus indique si le secret des identifiants OIDC est prêt, sans en exposer les valeurs.
| Champ | Description | Défaut | Validation |
|---|---|---|---|
secretName string | Nom du Secret qui contient les identifiants. | ||
ready boolean | Vrai quand le Secret d'identifiants est écrit et complet. | ||
lastRotatedAt Time | Date du dernier renouvellement des identifiants. | ||
observedRotationRequest string | Dernière demande de renouvellement prise en compte. |
SecretReference
SecretReference désigne un secret de votre tenant.
| Champ | Description | Défaut | Validation |
|---|---|---|---|
name string | Nom du secret. | MaxLength: 253 MinLength: 1 Pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ |
status.machineOriginis only filled in for machine applications created by the platform (see Machines and technical accounts).
Status and conditions
| Condition | True when |
|---|---|
Ready | the application exists in the SSO and matches the manifest |
CredentialsReady | the credentials Secret is written (or the credentials are kept in the SSO with create: false) |
Useful fields: status.provider.name (name of the application in the SSO, to pass to sng tenant policy attach --app), status.credentials.secretName, status.credentials.lastRotatedAt, status.lastSyncedAt.
| Reason | Condition | Meaning | Corrective action |
|---|---|---|---|
Reconciled | Ready=True, CredentialsReady=True | up to date | — |
SecretUpdated | CredentialsReady=True | the credentials were just renewed | restart the applications that read the Secret |
WaitingForTenant | Ready=False | the tenant's identity directory is not ready yet (the resource converges by itself) | wait; if it persists, contact support |
NamespaceNotManaged | Ready=False | the tenant is not activated on the platform side yet | contact support |
UnsupportedConfiguration | Ready=False | a validation rule is broken (URL, Secret name, token lifetime, assignableRoles set) | fix the manifest, sng apply |
SecretOwnershipConflict | CredentialsReady=False | a Secret with the same name exists and does not belong to this application | change credentialsSecret.name or delete the other Secret |
CredentialsMissing | CredentialsReady=False | the Secret could not be written or is incomplete | wait for the next attempt; if it persists, contact support |
CredentialsUnavailable | CredentialsReady=False | the application exists in the SSO but its Secret has disappeared, and the client secret cannot be read back | delete and recreate the application with deletionPolicy: Delete, or contact support |
InsufficientRBAC | CredentialsReady=False | platform-side incident: the Secret cannot be written | contact support |
ProviderConflict | Ready=False | an application with the same name exists in the SSO and does not belong to this object | choose another metadata.name (see Common errors) |
ProviderUnavailable, ScopeUnresolved | Ready=False | registering a machine application is not possible for now | automatic retry |
DependencyInUse | Ready=False | deletion blocked (deletionPolicy: Block): suppression bloquée : l'application est encore liée à 1 fournisseur d'identité | contact support; or delete with deletionPolicy: Delete |
What happens when you apply
Creation. The application is created in your users' directory under a stable name derived from the manifest (sng-<empreinte>-app-<nom>, visible in status.provider.name), with a clientId and a clientSecret, stored in the <nom>-oidc Secret in your tenant (unless credentialsSecret.create: false).
Update. A new sng apply updates the application in place; clientId and clientSecret do not change. Renaming the manifest (metadata.name) creates another application.
What happens when you delete
sng kind delete IAMApplication <nom>. The effect depends on deletionPolicy:
deletionPolicy | Application in the directory | <nom>-oidc Secret |
|---|---|---|
Block (default) | deleted, except while it is in use: linked to an external identity provider (DependencyInUse, with a message that says what) | deleted |
Orphan | kept | kept |
Delete | deleted, without checking usage | deleted |
Once the application is deleted from the directory, your users can no longer sign in to it. A blocked deletion is re-examined every minute and completes on its own as soon as the application is no longer in use.
Recreate under the same name. After a completed deletion (Block or Delete), a new
sng apply of the same manifest creates a new application, with a new clientId and a new
clientSecret in <nom>-oidc. After an Orphan, the reapplied manifest takes over the
application left in the directory.
No directory user is ever deleted along with an application.
Common errors
| Symptom | Cause | Fix |
|---|---|---|
sng apply rejects: metadata : seul name est permis (…) | label, annotation or any key other than name in metadata | remove it |
Ready: False, UnsupportedConfiguration: assignableRoles: field not supported yet… | assignableRoles set | remove the field |
Ready: False, WaitingForTenant | the tenant's directory is not ready yet | wait a few minutes; otherwise contact support |
sng apply rejects directory | directory changed after creation, or tenant combined with multiTenant or the urn:stackngo:introspect scope | create another application |
Ready: False, UnsupportedConfiguration: redirectURLs: … | redirect URL over http:// to a public host, or a private address | HTTPS, or http://127.0.0.1 for a native application |
sng apply rejects token.expireInHours | value 0 | at least 1, or remove spec.token (168 h) |
CredentialsReady: False, SecretOwnershipConflict | a <nom>-oidc Secret already exists (created by hand, or by another application) | credentialsSecret.name: autre-nom |
Ready: False, ProviderConflict: une ressource du même nom existe déjà et appartient à un autre objet : choisissez un autre nom | an application of that name exists in the directory without belonging to your tenant or to a deleted manifest | choose another metadata.name |
Deletion that never finishes, DependencyInUse | application linked to an external identity provider | contact support |
sng tenant policy attach --app billing-api has no effect | --app expects the SSO name, not the manifest name | read status.provider.name (sng kind get IAMApplication billing-api --json) and pass it to --app |