OAuth Integration Guide
Add "Continue with Oasis" to your application in minutes.
1. Register Your App
Go to Developer Appsand create a new OAuth app. You'll receive a client_id and client_secret.
2. The Button
Use the official Oasis logo and button style so users immediately recognize the sign-in option.
oasis_logo.svg
Official Oasis OAuth logo · SVG · 61×51px
Button guidelines
• Use the exact text "Continue with Oasis" — do not alter the wording
• Always include the Oasis logo to the left of the text
• Minimum button height: 40px · Minimum logo size: 16×14px
• Recommended style: black background (#000), white text (#fff), 8px border radius
• Do not recolor, distort, or modify the logo
HTML
<!-- Download the Oasis logo: https://oasisbio.oasiscompany.org/assets/oasis_logo.svg -->
<a href="https://oasisbio.oasiscompany.org/oauth/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URI&response_type=code&scope=profile+email&state=RANDOM_STATE&code_challenge=YOUR_CODE_CHALLENGE&code_challenge_method=S256"
style="display:inline-flex;align-items:center;gap:10px;padding:10px 20px;
background:#000;color:#fff;border-radius:8px;text-decoration:none;
font-family:sans-serif;font-size:15px;font-weight:500;">
<img src="https://oasisbio.oasiscompany.org/assets/oasis_logo.svg" width="20" height="17" alt="Oasis" />
Continue with Oasis
</a>React / Next.js
import Image from 'next/image';
function ContinueWithOasis({ clientId, redirectUri }: { clientId: string; redirectUri: string }) {
const handleClick = async () => {
const verifier = generateRandomString(64);
const challenge = base64url(await sha256(verifier));
sessionStorage.setItem('pkce_verifier', verifier);
const url = new URL('https://oasisbio.oasiscompany.org/oauth/authorize');
url.searchParams.set('client_id', clientId);
url.searchParams.set('redirect_uri', redirectUri);
url.searchParams.set('response_type', 'code');
url.searchParams.set('scope', 'profile email');
url.searchParams.set('state', generateRandomString(16));
url.searchParams.set('code_challenge', challenge);
url.searchParams.set('code_challenge_method', 'S256');
window.location.href = url.toString();
};
return (
<button
onClick={handleClick}
style={{ display:'inline-flex', alignItems:'center', gap:10,
padding:'10px 20px', background:'#000', color:'#fff',
borderRadius:8, border:'none', cursor:'pointer',
fontSize:15, fontWeight:500 }}
>
<Image src="https://oasisbio.oasiscompany.org/assets/oasis_logo.svg" width={20} height={17} alt="Oasis" />
Continue with Oasis
</button>
);
}3. Build the Authorization URL
Redirect users to this URL to start the OAuth flow:
const codeVerifier = generateRandomString(64); // store this
const codeChallenge = base64url(sha256(codeVerifier));
const authUrl = new URL('https://oasisbio.oasiscompany.org/oauth/authorize');
authUrl.searchParams.set('client_id', YOUR_CLIENT_ID);
authUrl.searchParams.set('redirect_uri', YOUR_REDIRECT_URI);
authUrl.searchParams.set('response_type', 'code');
authUrl.searchParams.set('scope', 'profile email oasisbios:read');
authUrl.searchParams.set('state', generateRandomString(16));
authUrl.searchParams.set('code_challenge', codeChallenge);
authUrl.searchParams.set('code_challenge_method', 'S256');
window.location.href = authUrl.toString();PKCE is required. Store code_verifier in session storage.
4. Exchange Code for Tokens
After the user authorizes, they're redirected to your redirect_uri with a code parameter. Exchange it:
const response = await fetch('https://oasisbio.oasiscompany.org/api/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
client_id: YOUR_CLIENT_ID,
client_secret: YOUR_CLIENT_SECRET,
code: CODE_FROM_REDIRECT,
redirect_uri: YOUR_REDIRECT_URI,
code_verifier: STORED_CODE_VERIFIER,
}),
});
const { access_token, refresh_token, expires_in } = await response.json();5. Access User Data
Use the access token as a Bearer token:
// Get user profile
const profile = await fetch('https://oasisbio.oasiscompany.org/api/oauth/userinfo', {
headers: { Authorization: `Bearer ${access_token}` },
}).then(r => r.json());
// { sub, username, display_name, avatar_url, email }
// Get character list (requires oasisbios:read scope)
const characters = await fetch('https://oasisbio.oasiscompany.org/api/oauth/resources/oasisbios', {
headers: { Authorization: `Bearer ${access_token}` },
}).then(r => r.json());
// Get DCOS documents (requires dcos:read scope)
const dcos = await fetch(`https://oasisbio.oasiscompany.org/api/oauth/resources/oasisbios/${bioId}/dcos`, {
headers: { Authorization: `Bearer ${access_token}` },
}).then(r => r.json());Available Scopes
profileusername, display name, avatar URLemailemail addressoasisbios:readcharacter list (title, slug, cover image)oasisbios:fullfull character data (abilities, worlds, eras, references)dcos:readDCOS document contentRefreshing Tokens
Access tokens expire after 1 hour. Use the refresh token to get a new one:
const response = await fetch('https://oasisbio.oasiscompany.org/api/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'refresh_token',
client_id: YOUR_CLIENT_ID,
client_secret: YOUR_CLIENT_SECRET,
refresh_token: STORED_REFRESH_TOKEN,
}),
});
// Returns new access_token and refresh_token (old one is invalidated)OIDC Discovery
Machine-readable configuration available at: /api/oauth/.well-known/openid-configuration