Documentation

Integrate PESU Auth into your app.

Overview

PESU Auth implements OAuth 2.0 Authorization Code flow with PKCE. Your app redirects users here to authenticate, receives an authorization code, exchanges it for tokens, then fetches user data.

1Create Client
2Generate PKCE
3Redirect User
4Exchange Code
5Fetch User

1. Create a Client

Go to /admin and create an OAuth client. You'll receive a client_id. For public clients (SPAs, mobile apps), no secret is needed — PKCE handles security.

Client Types
Public

SPAs, mobile apps, CLIs. No secret, PKCE required.

Confidential

Backend servers. Has secret + PKCE for extra security.

2. Generate PKCE

PKCE prevents authorization code interception attacks. Generate a randomcode_verifier, then create a code_challenge by SHA-256 hashing it.

javascript19 lines
12345678910111213141516171819
// Generate code_verifier (random string)
const codeVerifier = crypto.randomUUID() + crypto.randomUUID();

// Generate code_challenge (SHA-256 hash, base64url encoded)
async function generateChallenge(verifier) {
  const encoder = new TextEncoder();
  const data = encoder.encode(verifier);
  const hash = await crypto.subtle.digest('SHA-256', data);
  
  return btoa(String.fromCharCode(...new Uint8Array(hash)))
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=+$/, '');
}

const codeChallenge = await generateChallenge(codeVerifier);

// Store verifier for later (you'll need it for token exchange)
sessionStorage.setItem('code_verifier', codeVerifier);

3. Redirect to Authorize

Send users to the authorization endpoint with your client details and PKCE challenge.

javascript12 lines
123456789101112
const authUrl = new URL('https://your-domain.com/oauth2/authorize');

authUrl.searchParams.set('response_type', 'code');
authUrl.searchParams.set('client_id', 'YOUR_CLIENT_ID');
authUrl.searchParams.set('redirect_uri', 'https://yourapp.com/callback');
authUrl.searchParams.set('scope', 'profile:basic profile:contact');
authUrl.searchParams.set('state', crypto.randomUUID()); // CSRF protection
authUrl.searchParams.set('code_challenge', codeChallenge);
authUrl.searchParams.set('code_challenge_method', 'S256');

// Redirect user
window.location.href = authUrl.toString();

4. Exchange Code for Token

After user authorizes, they're redirected back with a code. Exchange it for tokens using your stored code_verifier.

javascript26 lines
1234567891011121314151617181920212223242526
// Get code from URL params
const code = new URLSearchParams(window.location.search).get('code');
const codeVerifier = sessionStorage.getItem('code_verifier');

const response = await fetch('https://your-domain.com/api/oauth2/token', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
  },
  body: new URLSearchParams({
    grant_type: 'authorization_code',
    code: code,
    redirect_uri: 'https://yourapp.com/callback',
    client_id: 'YOUR_CLIENT_ID',
    code_verifier: codeVerifier,
  }),
});

const tokens = await response.json();
// {
//   access_token: "...",
//   token_type: "Bearer",
//   expires_in: 3600,
//   refresh_token: "...",
//   scope: "profile:basic profile:contact"
// }

5. Fetch User Info

Use the access token to retrieve user data. Only fields the user consented to will be returned.

javascript16 lines
12345678910111213141516
const response = await fetch('https://your-domain.com/api/v1/user', {
  headers: {
    'Authorization': `Bearer ${accessToken}`,
  },
});

const user = await response.json();
// {
//   name: "John Doe",
//   prn: "PES1202504001",
//   srn: "PES1UG25CS001",
//   email: "john@example.com",
//   phone: "9876543210"
// }

console.log(`Welcome, ${user.name}!`);

Available Scopes

Request only what you need. Users see exactly what you're asking for.

ScopeFields
profile:basicRead your basic identity (Name, PRN, SRN).
profile:academicRead your academic details (Program, Branch, Semester, Section, Campus).
profile:photoRead your profile photo.
profile:contactRead your contact information (Email, Phone Number).

Error Handling

ErrorCause
invalid_clientUnknown client_id or wrong secret
invalid_grantCode expired, already used, or PKCE mismatch
invalid_tokenAccess token expired or revoked
insufficient_scopeUser didn't consent to any fields
access_deniedUser clicked "Deny" on consent screen

Try It

Test the full flow interactively without writing code.

Open OAuth Tester →