Other applications can offer Sign in with AppMint. The person is sent to AppMint, signs in on the normal Studio sign-in page and comes back to the application already signed in. AppMint acts as the identity provider. It supports OpenID Connect (OAuth 2.0 authorization code with PKCE) and SAML 2.0.
Video tutorials for this topic
The first app to use this is SpinForge webmail. Signing in there opens a hosted mailbox that is assigned to the person.
Who does what
| Who | What they do |
|---|---|
| Platform admin (root admin) | Registers each app under System Operations › Sign-in Apps, then hands the app's details to the app's team. |
| The app's team | Configures their app to use AppMint as its OpenID Connect or SAML provider. |
| People | Click Sign in with AppMint in the app, then sign in to Studio as they always do. |
Registered apps are platform-wide. One registration serves every organization. Sign-in Apps only appears in the root and shared organizations, and only root admins can use it.
Addresses to give an app
The identity provider runs on your AppEngine API under /idp. The issuer is https://<your-appengine>/idp. The top of Sign-in Apps shows the exact values under Give these to the app, each with a copy button.
| What | Address |
|---|---|
| Issuer | https://<your-appengine>/idp |
| Discovery URL | https://<your-appengine>/idp/.well-known/openid-configuration |
| Signing keys (JWKS) | https://<your-appengine>/idp/.well-known/jwks.json |
| Authorize | https://<your-appengine>/idp/oauth/authorize |
| Token | https://<your-appengine>/idp/oauth/token |
| UserInfo | https://<your-appengine>/idp/oauth/userinfo |
| Revoke · Introspect | https://<your-appengine>/idp/oauth/revoke · …/oauth/introspect |
| Sign out (RP-initiated logout) | https://<your-appengine>/idp/oauth/logout |
| SAML metadata URL | https://<your-appengine>/idp/saml/metadata |
| SAML single sign-on | https://<your-appengine>/idp/saml/sso (HTTP-Redirect or HTTP-POST) |
An OpenID Connect app only needs the discovery URL, because it finds every endpoint and key from there. A SAML app reads the metadata URL instead.
Register an app
Open System Operations › Sign-in Apps and click Register app. The drawer is one page:
Name (required). This is what people see while they sign in, for example Continue to SpinForge Mail.
How it signs in. OpenID Connect suits most web and mobile apps, and SAML 2.0 is for older business apps that require it. You cannot change this once the app is registered.
Sign in with AppMint. This switch is On by default. Turn it Off to pause the app: nobody can sign in to it until you turn it back on.
OpenID Connect settings
| Field | What to enter |
|---|---|
| Redirect URLs (required) | Where AppMint may send people back after they sign in. AppMint matches each URL exactly. It must use https, except http is allowed for localhost and 127.0.0.1. No wildcards and no #fragment. |
| After sign-out URLs | Where the app may send people after they sign out. Optional, with the same rules. |
| What the app may ask for | Scopes. openid (who signed in) is always on. email gives their email: the sign-in email or the picked mailbox. profile gives name and picture. org gives which organization they belong to. offline_access keeps them signed in with a refresh token. |
| Refresh tokens | Allowed by default. This switch alone decides whether the app gets refresh tokens. Asking for offline_access does not matter. |
| Public client | Off (Confidential — signs in with a client secret) for apps with a server that can keep a secret. Turn it on (Public — no secret, PKCE only) for apps that run entirely in a browser or on a phone. |
Every app must use PKCE with S256, confidential or public. Only the authorization code flow (response_type=code) is offered. A confidential app sends its secret to the token endpoint using HTTP Basic (client_secret_basic). A public app sends client_id and code_verifier.
SAML settings
| Field | What to enter |
|---|---|
| Entity ID (required) | The app's service provider entity ID |
| ACS URL (required) | Where AppMint posts the sign-in answer (HTTP-POST). https only. |
| Sign-out URL | Single logout URL. Optional. |
| Name ID | Email address, or Persistent id, which stays the same if the email changes |
| App's signing certificate | PEM. Only needed when the app signs its sign-in requests. |
AppMint signs its assertions.
Email the app receives
- Sign-in email: the email the person signs in to AppMint with.
- A mailbox they pick: the token's email is one of the mailboxes assigned to them, not their sign-in email. Use this for a webmail that should open that mailbox. Then choose Mailboxes from, the mail system to offer mailboxes from, such as SpinForge Mail. Choose Any mailbox assigned to them to offer every mailbox they have.
The list of apps shows this choice as Sign-in email or Picked mailbox (…).
Who may sign in
- People: staff (users of an organization). The form also offers Customers, but sign-in through AppMint currently accepts staff accounts only. A customer is told Only staff accounts can sign in to this app.
- Organizations: the org ids whose people may sign in. Leave it empty to allow every organization.
Locked, inactive and suspended users cannot sign in to any app.
Save, and copy the client secret
Click Register app. For a confidential OpenID Connect app, the drawer then shows the Client secret once (Copy it now — it is not shown again). The secret is not stored anywhere, so it can't be looked up later. If it is lost, rotate it.
When you open a registered app, you see:
- Client ID (
amc_…) with a copy button. - Rotate secret, for confidential apps. Click it, then Click again to rotate — the old secret stops working. The new secret is shown once, and the old one stops working straight away.
- Share with the app: everything the app's team needs, as one block with Copy all. For OpenID Connect that is the issuer, discovery URL, client ID, how the secret is handled, scopes, redirect URIs and which email claim to expect. For SAML it is the metadata URL, entity ID, ACS URL and Name ID. The secret is never part of this block, so send it to them separately.
If you switch an existing app to Public client, its secret stops working when you save. If you switch it back to confidential, rotate to get a new secret.
Delete app (with confirmation) stops every sign-in through the app at once, and its client ID stops working. To pause an app instead, turn Sign in with AppMint off.
What people see when they sign in
- In the app, they click Sign in with AppMint and are sent to AppMint.
- Studio's sign-in page appears, unless they are already signed in to Studio in this browser. AppMint has no second login screen. Two-factor and new-device checks apply as usual.
- The Continue to <App> card shows their organization and sign-in email. It also has a Use another organization link, which signs them out of Studio and back in so they can pick a different organization.
- What happens next depends on the app:
- An app that receives the sign-in email goes straight back to the app.
- An app that opens a mailbox asks Which mailbox do you want to open? every time, even if the person has only one mailbox. To switch mailbox, sign in again. The list shows the mailboxes assigned to them in that organization: active email accounts, from the mail system set in Mailboxes from. They click one and are sent back to the app.
- The app receives the person. For a mailbox app, the token's
emailis the mailbox they picked, withemail_verified: true.
If the person has no mailbox for the app, sign-in stops at the card with You have no <App> mailbox in <Organization>. They can Use another organization, or click Cancel and go back and ask an admin to assign them a mailbox under Configuration › Email Accounts.
A sign-in must be finished within 10 minutes and in the same browser. Otherwise the person sees This sign-in has expired or was opened in another browser. Start again from the app.
AppMint checks the mailbox each time the app uses the person's sign-in, for example to refresh a token or read their details. If the mailbox has been unassigned, that check fails and the app no longer gets the person. The same happens when a user is locked or deactivated.
Tokens and claims
| Claim | Scope | Value |
|---|---|---|
sub | openid | Identifies the person in their organization. For a mailbox app, it also identifies the mailbox, so each mailbox is a different sub. |
email, email_verified | email | The sign-in email or picked mailbox. email_verified is always true. |
name, given_name, family_name, picture | profile | From the person's user record |
org, org_name | org | The organization they signed in to |
The ID token carries these claims as well as UserInfo, because mail servers read the email from the ID token. Tokens are signed with RS256.
| Lifetime | |
|---|---|
| Access token, ID token | 1 hour |
| Refresh token | 30 days |
| AppMint sign-in session for apps | 14 days |
Registered apps are first-party, so there is no consent screen. The app receives the scopes it was registered for.
Set up SpinForge webmail sign-in
In this setup, people open their SpinForge Mail mailbox by signing in with AppMint, with no separate mailbox password to remember.
- In Sign-in Apps, click Register app:
- Name:
SpinForge Mail - How it signs in: OpenID Connect
- Redirect URLs: the webmail's sign-in callback URL, which the SpinForge team provides
- What the app may ask for:
openid,emailandprofile. Addoffline_accessif webmail should keep people signed in. - Email the app receives: A mailbox they pick, with Mailboxes from set to SpinForge Mail
- Public client: on. The webmail is a browser app, so it signs in with PKCE and has no client secret.
- Name:
- Open the app and click Copy all in its Share with the app box.
- Send that to SpinForge: the issuer (
https://<your-appengine>/idp), the client ID and the scopes. There is no secret to send. - SpinForge switches on Sign in with AppMint in its webmail and mail server with those values. That setup is on SpinForge's side, not in AppMint; ask SpinForge to confirm when it is live. The token's
emailis the mailbox the person picked, and that is the mailbox webmail opens. - In Studio, assign the mailboxes under Configuration › Email Accounts › Assign to people or AI — to a person, or to a group they are in.
For operators: production keys
The identity provider needs three values in production. Keep them in a secret store, never in a committed env file.
| Variable | What it is |
|---|---|
IDP_SIGNING_KEY | RSA private key (PEM). Signs ID tokens and SAML assertions. Whoever holds it can sign anyone in. |
IDP_SIGNING_CERT | X.509 certificate (PEM) for that key. The SAML metadata publishes it, and OpenID Connect publishes the public key as a JWK. |
IDP_SECRET | A random string. It signs the identity provider's cookies, and every app's client secret is derived from it. |
scripts/idp-keys.ts in AppEngine generates a key, a 5-year certificate and a secret, then prints the command that stores them as a Kubernetes secret. It writes nothing to disk.
- In production, if any of the three is missing, the identity provider is switched off. Its endpoints answer Identity provider is not configured, and AppMint does not fall back to throwaway keys.
- Outside production, missing values are generated once and kept in the system's temp folder, so dev sign-ins survive a restart.
- Changing
IDP_SECRETchanges every app's client secret. Each confidential app then needs a rotated secret. - One identity provider for the platform. Today the keys and
IDP_SECRETare the platform's, set on the server. If organizations later use AppMint as their own sign-in provider, these may move into their configuration. - Replacing the signing key changes the published key ID. OpenID Connect apps pick the new key up from the JWKS URL, but SAML apps must reload the metadata.
