OAuth 2.0 Integration
Complete guide to integrating with SavePoint Authentication
Overview
SavePoint Authentication Portal supports OAuth 2.0 and OpenID Connect (OIDC) standards, allowing your applications to securely authenticate users without handling passwords directly. This guide covers the complete integration process.
OAuth 2.0
Industry-standard authorization framework for secure, delegated access to user data
OpenID Connect
Authentication layer on top of OAuth 2.0 providing user identity information
Getting Started
1. Register Your Application
Before integrating with SavePoint Authentication, you need to register your application:
- Contact SavePoint IT Support at support@savepoint.com.au
- Provide your application details (name, description, redirect URIs)
- Receive your Client ID and Client Secret
- Configure your application with the provided credentials
Required Information
- Application name and description
- Redirect URIs (must be HTTPS in production)
- Application type (web, mobile, SPA)
- Requested scopes and permissions
Authorization Code Flow
The Authorization Code flow is the most secure OAuth 2.0 flow for web applications. It involves redirecting the user to SavePoint for authentication and receiving an authorization code.
Step 1: Authorization Request
Redirect the user to the SavePoint authorization endpoint:
GET https://auth.savepoint.com.au/oauth/authorize? response_type=code& client_id=YOUR_CLIENT_ID& redirect_uri=https://yourapp.com/callback& scope=openid profile email& state=random_state_value& code_challenge=BASE64URL_ENCODED_CHALLENGE& code_challenge_method=S256
Step 2: User Authorization
The user will be presented with a login page and consent screen. After successful authentication and consent, they'll be redirected back to your application with an authorization code.
Step 3: Exchange Code for Tokens
Exchange the authorization code for access and ID tokens:
POST https://auth.savepoint.com.au/oauth/token Content-Type: application/x-www-form-urlencoded grant_type=authorization_code& code=AUTHORIZATION_CODE& redirect_uri=https://yourapp.com/callback& client_id=YOUR_CLIENT_ID& client_secret=YOUR_CLIENT_SECRET& code_verifier=ORIGINAL_RANDOM_STRING
Step 4: Use Access Token
Use the access token to make authenticated requests:
GET https://auth.savepoint.com.au/oauth/userinfo Authorization: Bearer ACCESS_TOKEN
Available Scopes
Scopes define the level of access your application requests from the user:
openid
Required for OpenID Connect. Provides access to the user's unique identifier.
profile
Access to the user's profile information (name, picture, etc.).
email
Access to the user's email address and email verification status.
offline_access
Request a refresh token for long-term access without user interaction.
read:users
Read access to user information (requires admin approval).
manage:sessions
Manage user sessions and authentication state.
Code Examples
JavaScript / Node.js
const express = require('express');
const crypto = require('crypto');
const app = express();
// Configuration
const CLIENT_ID = 'your_client_id';
const CLIENT_SECRET = 'your_client_secret';
const REDIRECT_URI = 'https://yourapp.com/callback';
const AUTH_BASE_URL = 'https://auth.savepoint.com.au';
// Generate PKCE challenge
function generatePKCE() {
const codeVerifier = crypto.randomBytes(32).toString('base64url');
const codeChallenge = crypto
.createHash('sha256')
.update(codeVerifier)
.digest('base64url');
return { codeVerifier, codeChallenge };
}
// Start OAuth flow
app.get('/login', (req, res) => {
const { codeVerifier, codeChallenge } = generatePKCE();
const state = crypto.randomBytes(16).toString('hex');
// Store state and codeVerifier in session
req.session.state = state;
req.session.codeVerifier = codeVerifier;
const authUrl = new URL('/oauth/authorize', AUTH_BASE_URL);
authUrl.searchParams.set('response_type', 'code');
authUrl.searchParams.set('client_id', CLIENT_ID);
authUrl.searchParams.set('redirect_uri', REDIRECT_URI);
authUrl.searchParams.set('scope', 'openid profile email');
authUrl.searchParams.set('state', state);
authUrl.searchParams.set('code_challenge', codeChallenge);
authUrl.searchParams.set('code_challenge_method', 'S256');
res.redirect(authUrl.toString());
});
// Handle callback
app.get('/callback', async (req, res) => {
const { code, state } = req.query;
if (state !== req.session.state) {
return res.status(400).send('Invalid state');
}
try {
const tokenResponse = await fetch(`${AUTH_BASE_URL}/oauth/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
grant_type: 'authorization_code',
code,
redirect_uri: REDIRECT_URI,
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
code_verifier: req.session.codeVerifier,
}),
});
const tokens = await tokenResponse.json();
// Store tokens securely
req.session.accessToken = tokens.access_token;
req.session.idToken = tokens.id_token;
res.redirect('/dashboard');
} catch (error) {
console.error('Token exchange failed:', error);
res.status(500).send('Authentication failed');
}
});React / Next.js
import { createAuthClient } from '@better-auth/react';
const authClient = createAuthClient({
baseURL: 'https://auth.savepoint.com.au',
plugins: [
// Add any required plugins
],
});
export default function LoginButton() {
const { signIn, data: session, isPending } = authClient.useSession();
const handleLogin = async () => {
try {
await signIn.social({
provider: 'savepoint',
callbackURL: '/dashboard',
});
} catch (error) {
console.error('Login failed:', error);
}
};
if (session) {
return (
<div>
<p>Welcome, {session.user.name}!</p>
<button onClick={() => authClient.signOut()}>
Sign Out
</button>
</div>
);
}
return (
<button
onClick={handleLogin}
disabled={isPending}
className="bg-blue-600 text-white px-4 py-2 rounded"
>
{isPending ? 'Signing in...' : 'Sign in with SavePoint'}
</button>
);
}Security Considerations
Critical Security Requirements
- Always use HTTPS for redirect URIs in production
- Implement PKCE (Proof Key for Code Exchange) for public clients
- Validate the
stateparameter to prevent CSRF attacks - Store client secrets securely (never in client-side code)
- Implement proper token storage and rotation
Token Security
- • Store tokens securely (encrypted cookies, secure storage)
- • Implement automatic token refresh
- • Set appropriate token expiration times
- • Log and monitor token usage
Application Security
- • Validate all redirect URIs
- • Implement rate limiting
- • Use secure session management
- • Regular security audits
Well-Known Endpoints
SavePoint Authentication provides standard discovery endpoints for automatic configuration:
/.well-known/openid_configuration
OpenID Connect Discovery document containing endpoint URLs and supported features.
View Discovery Document →/.well-known/oauth-authorization-server
OAuth 2.0 Authorization Server Metadata document.
View OAuth Metadata →Testing Your Integration
Development Environment
- Use
http://localhostURLs for local testing - Test all OAuth flows (authorization code, refresh token)
- Verify error handling for invalid credentials and expired tokens
- Test PKCE implementation for security
Common Issues
Redirect URI Mismatch
Ensure the redirect URI in your request exactly matches the one registered with SavePoint.
Invalid Client Credentials
Verify your Client ID and Client Secret are correct and haven't been rotated.
CORS Issues
For client-side applications, ensure your domain is registered for CORS access.