Authentication for your applications
Deployed and supported. The fields and commands described here are stable within version v1alpha1.
Your applications can entrust the sign-in of their users to StackNGO: you declare an OIDC application in YAML, StackNGO creates the OAuth2 client and makes clientId, clientSecret and issuer available, ready to be passed to your App. Your users sign in on a page in your organization's colors (Sign-in page), without a password (Sign-in providers), and your application receives a standard OIDC token.
apiVersion: iam.stackngo.io/v1alpha1
kind: IAMApplication
metadata:
name: billing-api
spec:
directory: tenant # the users of YOUR applications
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
A few moments later, the billing-api-oidc credentials are ready to be used by your App.
Two directories, two issuers
The directory field chooses who signs in to the application:
directory | Who signs in | Issuer |
|---|---|---|
tenant | the users of your applications (tenant directory) | an issuer specific to your tenant: https://auth.dev.stackngo.fr/t/acme |
platform (default) | your tenant's members on StackNGO (internal tools, machine identities) | the platform issuer |
For an application meant for your customers, always set directory: tenant. The field can no longer be changed after creation: to change directory, create another application. It is incompatible with the urn:stackngo:introspect scope.
A token issued for your tenant's directory is valid only for it: it is rejected by the StackNGO API and by another tenant's issuer.
Prerequisites
- A session on the tenant:
sng tenant use acme. deploy:write(policyreadwriteoradmin).
Steps
1. Generate and complete the manifest
sng template gen IAMApplication billing-api > billing-api.yml
Add directory: tenant under spec if the template does not have it. The useful fields:
| Field | Role | Notes |
|---|---|---|
directory | which users sign in | tenant or platform (default); cannot be changed |
displayName | name shown on the sign-in screen | 256 characters max |
homeURL | the application's home page | HTTPS; no local or private address |
redirectURLs | OAuth2 return URLs | HTTPS, except http://127.0.0.1 / http://localhost for a native application or a CLI; 32 max |
postLogoutRedirectURLs | addresses allowed after a sign-out | same rules; without them, sign-out does not redirect |
grantTypes | allowed flows | authorization_code, refresh_token, client_credentials; 16 max |
scopes | offered scopes | openid, profile, email…; 32 max |
public | public client (native application, CLI) | PKCE required, no secret |
token.expireInHours | access token lifetime | 1 to 8760; 168 h if omitted (0 forbidden) |
token.refreshExpireInHours | refresh token lifetime | 168 if refresh_token is in grantTypes; 0 forbidden with refresh_token |
credentialsSecret.name | name under which the credentials are made available to your Apps | <name>-oidc by default |
deletionPolicy | Block (default), Orphan, Delete | see Limits |
2. Apply
sng apply billing-api.yml
IAMApplication/billing-api created
The console (Authentication section, Applications page) offers the same form, already prefilled with directory: tenant, and shows which applications sign in your users.
3. Use the credentials
A few moments after applying, the credentials are ready under the name billing-api-oidc (or that of credentialsSecret.name), with three keys:
| Key | Content |
|---|---|
clientId | OAuth2 client identifier |
clientSecret | client secret |
issuer | URL of your tenant's OIDC issuer (https://auth.dev.stackngo.fr/t/acme) |
Reference them in your App as a secret:
apiVersion: deploy.stackngo.io/v1alpha1
kind: App
metadata:
name: billing-api
spec:
services:
api:
image: ovh-gra-0.registry.dev.stackngo.fr/acme/billing-api:1.0.0
ports: ["8080"]
ingress: { port: 8080 }
env:
OIDC_ISSUER: { secret: billing-api-oidc, key: issuer }
OIDC_CLIENT_ID: { secret: billing-api-oidc, key: clientId }
OIDC_CLIENT_SECRET: { secret: billing-api-oidc, key: clientSecret }
OIDC discovery is served under <issuer>/.well-known/openid-configuration: any OIDC library is happy with it.
For an application that does not run on the platform, read the credentials with sng iam app credentials billing-api (action auth:ReadCredentials, policy admin).
4. What the token contains
The identity token (ID token) and the access token are signed JWTs (RS256). For a user of your directory, they carry:
| Claim | Content |
|---|---|
iss | your tenant's issuer |
sub | stable account identifier (the same as in sng iam user list) |
email, email_verified | the account's address (with the email scope) |
tenant | your tenant's name |
directory | tenant |
roles | the account's roles (absent if it has none) |
permissions | the set of permissions of its roles (absent if there are none) |
Tokens never reveal the other tenants a person may be a member of.
5. Verify the token in the application
Your application must verify the signature (public keys announced by discovery), the issuer (iss equal to issuer), the audience (aud equal to your clientId) and the expiry, then read roles and permissions. Go example with go-oidc:
provider, err := oidc.NewProvider(ctx, os.Getenv("OIDC_ISSUER"))
if err != nil { log.Fatal(err) }
verifier := provider.Verifier(&oidc.Config{ClientID: os.Getenv("OIDC_CLIENT_ID")})
idToken, err := verifier.Verify(ctx, rawIDToken) // signature, iss, aud, exp
if err != nil { /* refuse: 401 */ }
var claims struct {
Subject string `json:"sub"`
Email string `json:"email"`
Roles []string `json:"roles"`
Permissions []string `json:"permissions"`
}
if err := idToken.Claims(&claims); err != nil { /* refuse */ }
if !slices.Contains(claims.Permissions, "tickets:reply") { /* 403 */ }
The permissions are the ones you defined in your roles; they are checked by your code.
6. Renew the secret
To change the clientSecret, renew it from the console (Renouveler le secret, under Authentification > Applications) or with the CLI. The new secret is written to billing-api-oidc; the clientId does not change.
sng iam app rotate billing-api
sng iam app credentials billing-api
The old secret is refused as soon as the renewal is processed, within seconds: then restart the applications that read the secret. This renewal is reserved for tenant administrators.
Verification
sng iam app list
sng kind get IAMApplication billing-api
The application appears with the "Users of your applications" directory and Ready: True. Then, from your application, start an authorization_code flow to the authorization endpoint announced by the issuer's discovery with the clientId: your organization's sign-in page is displayed.
Limits
- If the application still does not appear in
sng iam app listafter a few minutes, your tenant's directory may not be enabled yet: contact support. deletionPolicy: Block(default) delays deleting an application that is still in use, then deletes it as soon as it no longer is. A deleted application can be recreated under the same name, with new credentials.directory: tenantapplications have no access to the StackNGO API: their tokens open no session there.
Going further
- An
IAMApplicationwith theclient_credentialsflow can serve as a machine identity to call the StackNGO API: see Machine identities. - The directory's applications are named stably: renaming the manifest creates a new application.