Ansible offers app and website developers a free and open platform that lets people sign up and log in with their Ansible account instead of inventing another password.
Higher conversion
Users sign in with a few taps, boosting conversion and retention.
No passwords to keep
Nothing to store, reset or leak — you never see a secret of theirs.
Direct communication channels
You can reach your users within Ansible, with built-in push notification support.
Further integration
You can deliver more services directly via the Bot API and Mini Apps.
Note: This document describes the Ansible Login library and the new OpenID Connect login flow.
Ansible offers a compact tool to quickly add Ansible login buttons to your interface. You can also directly access our library's JS API.
On mobile, use the standard OIDC redirect through the system browser — the same endpoints, no SDK required.
Alternatively, Ansible supports the standard OpenID Connect protocol. This allows you to integrate Ansible authentication into your application using any OIDC-compatible library or authentication platform (e.g., Keycloak, Authentik, Auth0 etc.).
Our implementation follows the standard Authorization Code Flow with PKCE support.
For an in-depth understanding of the general OIDC flow, please refer to the OpenID Foundation's Developer Guide.
@ansible_dev_bot bot, menu button opens https://id.ansible.su/app.client_id and
client_secret there too.https://id.ansible.su/widget.js to your page —
or go through plain OIDC.id_token on your server before
trusting anything the browser sent.Stuck on any of the steps above? Write to us and say which one.
Your app needs a card: the name and logo a user will see in the
confirmation sheet. You create it in the developer dashboard — open the
@ansible_dev_bot bot and press the menu button.
Use the logo from your site and the name that matches your address bar. People agree to hand over their data to someone they recognise; an unfamiliar name in that sheet is a reason to press Cancel.
Our client_id is not a bot id — it is a string like
app_9f3ab21cissued by the dashboard. The client_secret is shown in the same place, to the owner of the app only.
An app card holds two lists, and they mean different things:
https://example.com. No port, no path.https://example.com/auth/callback. Compared byte for byte: a
trailing slash makes it a different address.Important: logins only work from pre-registered addresses. That is not paperwork — without the check, someone else’s site could walk a user through the real confirmation sheet and keep the result.
Use the tool below to customize your button and get the HTML snippet for your website.
Alternatively, you can interact with the library using the following JS methods:
The library exposes one object, Ansible.
| Method | Description |
|---|---|
Ansible.login(clientId, callback) | Opens the login window and calls callback with the result. Both arguments are optional — without them the values come from the <script> tag attributes. |
There is no separate init step: the library is ready as soon as it loads.
Configured through attributes on the same
<script> tag.
| Attribute | Type | Description |
|---|---|---|
data-client | string | The client_id from the dashboard. When present, the library inserts a button in place of the tag. |
data-onauth | string | The name of a global function to call with the result. The name only: data-onauth="onAnsibleAuth", not onAnsibleAuth(data) — an expression will not run. |
data-label | string | Optional. The button caption. |
<script async src="https://id.ansible.su/widget.js"
data-client="app_9f3ab21c"
data-label="Войти через Ansible"
data-onauth="onAnsibleAuth"></script>
<script>
function onAnsibleAuth(data) {
// data.jwt приходит только first-party клиентам.
// Всё остальное проверяйте на своём сервере.
fetch('/auth/ansible', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
}
</script>The function named by data-onauth receives one
object.
| Field | Type | Description |
|---|---|---|
status | string | confirmed on success. |
user | object | The id and name of whoever logged in, plus auth_date. |
hash | string | HMAC-SHA256 over auth_date, id, name, photo_url, keyed with SHA-256 of your client_secret. Verify it server-side. |
jwt | string | First-party apps only. Not issued to ordinary clients. |
🚨 Only the fields listed above are covered by the signature. Anything that arrives alongside and is not part of
hashis browser-supplied: there is nothing to check it against, so do not make decisions on it.
If you are using an OIDC-compatible library or identity broker, you can use the standard configuration values below.
Discovery Document URL
https://id.ansible.su/.well-known/openid-configuration
Client Configuration
| Parameter | Value |
|---|---|
| Client ID | The Client ID from the developer dashboard |
| Client Secret | The Client Secret from the developer dashboard |
| Response Type | code |
| PKCE | Required (S256) |
We declare two scopes. openid is required.
| Scope | Description | Claims returned |
|---|---|---|
openid | Required. The user identifier and the auth timestamp. | sub, iss, aud, iat, exp, auth_time |
profile | The display name. | name, picture |
Login with Ansible returns no phone number and no email — we have no such scope. If you need a verified number, ask the user for it yourself: quietly handing someone’s phone to a third-party site is not a fair price for a convenient login.
picturecurrently comes back as an empty string: profile photos do not reach the token yet. The claim is declared and will not disappear — rely on the key, not on the value.
All the data arrives directly in the ID token.
A decoded id_token looks like this:
{
"iss": "https://id.ansible.su",
"aud": "app_9f3ab21c",
"sub": "1234567890",
"iat": 1753900000,
"exp": 1753903600,
"auth_time": 1753900000,
"name": "Мария",
"picture": "",
"nonce": "n-0S6_WzA2Mj"
}
subis a string even when it holds a number. Store it as text — not every identifier survives a parse to integer.
There is a /userinfo endpoint; it returns sub,
name and picture for a Bearer token, and nothing
beyond what the id_token already carries. OIDC libraries can skip
it.
If you are integrating the OIDC flow manually without a library, use the endpoints and flow details below.
https://id.ansible.su/.well-known/openid-configurationhttps://id.ansible.su/authorizehttps://id.ansible.su/tokenhttps://id.ansible.su/userinfohttps://id.ansible.su/.well-known/jwks.jsonConfiguring a library or an identity broker (Keycloak, Authentik, Auth0)? The discovery URL is all you need — it picks up the rest.
Send the user to the authorization endpoint in their browser.
GET https://id.ansible.su/authorize?
client_id=<YOUR_CLIENT_ID>&
redirect_uri=<YOUR_CALLBACK_URL>&
response_type=code&
scope=openid%20profile&
state=<RANDOM_STRING>&
code_challenge=<PKCE_CHALLENGE>&
code_challenge_method=S256
app_… string from the dashboard.base64url(sha256(verifier)).PKCE is required. Discovery advertises both
S256andplain, but a code exchange without acode_verifiercurrently fails withinvalid_grant. UseS256— it both works and is the right choice.
Once the user confirms, they return to your
redirect_uri with a code parameter. Exchange it from
your server, not from the browser.
POST https://id.ansible.su/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
code=<AUTHORIZATION_CODE>&
redirect_uri=<YOUR_CALLBACK_URL>&
client_id=<YOUR_CLIENT_ID>&
client_secret=<YOUR_CLIENT_SECRET>&
code_verifier=<PKCE_VERIFIER>
Client authentication is
client_secret_post: the secret goes in the request body. Our server does not read HTTP Basic, so anAuthorizationheader buys you nothing here.
Response:
{
"access_token": "...",
"token_type": "Bearer",
"expires_in": 3600,
"id_token": "eyJhbGciOiJSUzI1NiIs...",
"scope": "openid profile"
}
The code is single-use and lives 10 minutes. No refresh_token is
issued: an access_token lasts an hour, after which the user signs in
again.
The id_token is a signed JWT. Before trusting what
is inside, validate the signature:
https://id.ansible.su/.well-known/jwks.json — by the kid in the token
header.RS256.iss is https://id.ansible.su,
aud is your client_id, exp is not in the
past, and nonce matches the one you sent.There is one key today and it is not rotated, but the header already carries a
kid. Select by it rather than taking the first key in the list — otherwise the first rotation breaks logins, and for everyone at once.
Tokens are signed with RS256, using an RSA-2048 key.
No other algorithm is offered.
| Algorithm | Status |
|---|---|
RS256 | The only one. Works with every OIDC library out of the box. |
JWKS always holds exactly one active key. Choosing the algorithm per application is not supported.