Sign in with Castyr
The authorization code flow with PKCE, for web, single-page, mobile and desktop apps.
You send the user to Castyr, they approve, and Castyr sends them back with a short-lived code that you exchange for tokens.
Make a PKCE pair
For every sign-in, create a random code_verifier (43–128 characters) and derive the code_challenge
from it: base64url, no padding, of its SHA-256. Keep the verifier until the user comes back. Public clients
must do this; web apps should too.
// Browser or Node 18+
const b64url = (buf) => btoa(String.fromCharCode(...new Uint8Array(buf)))
.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
const verifier = b64url(crypto.getRandomValues(new Uint8Array(32)));
const challenge = b64url(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(verifier)));Send the user to Castyr
https://sso.castyr.cloud/oauth/authorize
?response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=https%3A%2F%2Fyourapp.example%2Fcallback
&scope=openid%20profile
&state=RANDOM_STATE
&code_challenge=CHALLENGE
&code_challenge_method=S256Prop
Type
If the user isn't signed in, Castyr asks them to sign in first. They then see a consent screen, unless they already approved these scopes for your app. Sensitive scopes always need their explicit approval once.
Handle the redirect back
https://yourapp.example/callback?code=AUTH_CODE&state=RANDOM_STATE&iss=https%3A%2F%2Fsso.castyr.cloud- Check that
stateis the value you sent, and thatissishttps://sso.castyr.cloud. - On failure you get
erroranderror_descriptioninstead ofcode: for exampleaccess_deniedwhen the user clicks Cancel, orlogin_required/consent_requiredwithprompt=none.
Problems with client_id or redirect_uri are shown to the user and never redirected, so they can't be used
to bounce people to other sites.
Exchange the code for tokens
Codes are single-use and expire after 5 minutes. Send the same redirect_uri and your verifier.
curl -X POST https://sso.castyr.cloud/oauth/token \
-u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \
-d grant_type=authorization_code \
-d code=AUTH_CODE \
-d redirect_uri=https://yourapp.example/callback \
-d code_verifier=VERIFIER{
"access_token": "cat_…",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "openid profile",
"refresh_token": "crt_…",
"id_token": "eyJ…"
}refresh_token is included when your app may refresh; id_token when you asked for openid. Using a code
twice fails, and also revokes the tokens that code already produced.
Next: call user info or verify the ID token, and keep the session alive with refresh tokens.