How it works
Ismilink uses the Authorization Code flow, recommended for websites and mobile apps.
- Register your application
In your Ismilink space, Developers tab: name, logo and allowed redirect URLs. You get a Client ID and a Client secret. - Redirect to Ismilink
Your button sends the user to /oauth/authorize. They sign in and accept the requested permissions. - Receive a code
Ismilink sends the user back to your redirect URL with a single-use code valid for 10 minutes. - Exchange it server-side
Your server exchanges the code for an access token, a refresh token and a signed id_token.
Endpoints
| Endpoint | URL |
|---|---|
| OpenID discovery | https://mylinkis.com/.well-known/openid-configuration |
| Authorization | https://mylinkis.com/oauth/authorize |
| Tokens | https://mylinkis.com/oauth/token |
| User profile | https://mylinkis.com/oauth/userinfo |
| Revocation | https://mylinkis.com/oauth/revoke |
| Public keys (JWKS) | https://mylinkis.com/oauth/jwks |
Permissions (scopes)
| Scope | Grants access to |
|---|---|
openid | A unique identifier to sign you in (OpenID Connect). |
profile | Name, username, photo, language and links to your public pages. |
email | The email address of your Ismilink account. |
links | The public links on your page (excluding locked links). |
portfolio | Title, bio and city shown on your published portfolio. |
1. Redirect the user
Build the authorization URL with your Client ID, a registered redirect URL, the permissions you need and a random state value you will check on return.
https://mylinkis.com/oauth/authorize
?response_type=code
&client_id=al_xxxxxxxxxxxx
&redirect_uri=https://ooyee.net/auth/ismilink/callback
&scope=openid%20profile%20email
&state=RANDOM_STATE
&code_challenge=BASE64URL_SHA256_VERIFIER
&code_challenge_method=S256If the user accepts, they come back to your redirect URL with ?code=…&state=…. If they decline, you receive ?error=access_denied.
2. Exchange the code
From your server only (never put the secret in the browser), exchange the code for tokens. Client authentication uses Basic auth or the request body.
const res = await fetch('https://mylinkis.com/oauth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Authorization: 'Basic ' + Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString('base64'),
},
body: new URLSearchParams({
grant_type: 'authorization_code',
code,
redirect_uri: 'https://ooyee.net/auth/ismilink/callback',
code_verifier, // if you used PKCE
}),
});
const { access_token, refresh_token, id_token, expires_in } = await res.json();$ch = curl_init('https://mylinkis.com/oauth/token');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_USERPWD => CLIENT_ID . ':' . CLIENT_SECRET,
CURLOPT_POSTFIELDS => http_build_query([
'grant_type' => 'authorization_code',
'code' => $_GET['code'],
'redirect_uri' => 'https://ooyee.net/auth/ismilink/callback',
]),
]);
$tokens = json_decode(curl_exec($ch), true);3. Read the profile
Call /oauth/userinfo with the header Authorization: Bearer <access_token>. Returned fields depend on the granted permissions.
{
"sub": "42",
"name": "Sara Benali",
"preferred_username": "sara",
"picture": "https://mylinkis.com/uploads/…",
"profile": "https://mylinkis.com/p/sara",
"website": "https://mylinkis.com/@sara",
"locale": "fr",
"email": "sara@example.com",
"email_verified": false
}Use the “sub” field as the user's stable identifier: it never changes, even if the user edits their name or email.
PKCE (public apps)
For an app without a server (mobile, SPA), tick “Public application”: no secret is used and PKCE becomes mandatory. Generate a code_verifier, send its SHA-256 hash as code_challenge, then pass the code_verifier during the exchange.
const verifier = base64url(crypto.getRandomValues(new Uint8Array(32)));
const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier));
const challenge = base64url(new Uint8Array(digest));Refresh and revoke
The access token expires after one hour. Use the refresh token to get a new one: it is replaced on every use (rotation). To sign a user out, revoke their tokens.
grant_type=refresh_token&refresh_token=alrt_…
# revoke a token (sign out)
POST /oauth/revoke token=alat_…The official button
Use this button so your users recognise Ismilink at a glance. Keep the label “Sign in with Ismilink” and a height of at least 44 px.
<a class="ismilink-btn" href="/auth/ismilink">
<img src="https://mylinkis.com/img/logo.png" alt="" width="22" height="22">
Sign in with Ismilink
</a>
<style>
.ismilink-btn{display:inline-flex;align-items:center;gap:12px;min-height:48px;padding:0 20px;
border-radius:14px;background:linear-gradient(135deg,#3d5afe,#7c3aed);color:#fff;
font:600 16px/1 system-ui,sans-serif;text-decoration:none;
box-shadow:0 10px 30px -10px rgba(124,58,237,.8),inset 0 1px 0 rgba(255,255,255,.25)}
.ismilink-btn:hover{filter:brightness(1.08)}
.ismilink-btn:focus-visible{outline:3px solid #6d28d9;outline-offset:2px}
</style>