”Who This Guide Is For
This guide is for full-stack developers integrating wearable device APIs into web applications. You should have solid understanding of Next.js, OAuth2 flows, and data visualization. If you're building wellness dashboards, health tracking platforms, or any application consuming wearable data, this guide is for you.
The fastest way to integrate wearable health data is combining OAuth2 with Next.js server-side fetching—we've unified 15+ wearable platforms for 250K+ users using these integration patterns. This guide covers OAuth2 authorization flows, secure token management, wearable API data fetching, and wellness dashboard visualization.
Wearable technology like the Oura Ring provides a wealth of personal health data. For developers, this data is a goldmine for creating personalized wellness applications. The challenge, however, lies in securely accessing and then meaningfully visualizing this data.
In this tutorial, we'll build a wellness dashboard that connects to the Oura Ring API, fetches your daily health metrics, and displays them in a clean, graphical interface. We'll be using a modern web stack: Next.js for our React framework and Recharts for data visualization.
By the end of this guide, you'll have a working web application and a solid understanding of how to integrate wearable tech APIs into your own projects. This is a practical skill for anyone interested in the booming health tech space.
Understanding the Problem
While the Oura app itself is excellent, you might want to correlate your Oura data with other data sources, create custom visualizations, or build a unique wellness application. The official Oura API is the gateway to these possibilities. However, integrating with any API, especially one that uses OAuth2 for authentication, can be tricky.
Our approach will be to create a Next.js application that handles the OAuth2 handshake, securely stores the access tokens, and then uses those tokens to fetch data from the Oura API. We'll then pass that data to our frontend to be rendered into insightful charts.
Prerequisites
- An Oura Ring and Oura account.
- Node.js (v18 or later) and npm installed.
- Basic knowledge of React and Next.js.
Step 1: Setting up your Oura API Application
First, we need to register a new application in the Oura developer portal.
What we're doing
We'll create an OAuth2 application to get a Client ID and Client Secret, which our Next.js app will use to authenticate with the Oura API.
Implementation
- Go to the "API Applications" section in your Oura developer portal and click "Create New Application".
- Fill in the application details.
- Once created, you will be provided with a Client ID and a Client Secret. Keep these safe; we'll need them in a moment.
Step 2: Initializing our Next.js Project
Now, let's get our Next.js application up and running.
What we're doing
We'll create a new Next.js project and set up our environment variables to securely store our Oura API credentials.
Implementation
npx create-next-app@latest oura-wellness-dashboard
cd oura-wellness-dashboard
Next, create a file named .env.local in the root of your project and add your Oura API credentials:
OURA_CLIENT_ID=your_client_id
OURA_CLIENT_SECRET=your_client_secret
NEXTAUTH_URL=http://localhost:3000
How it works
The .env.local file is a special file in Next.js for storing environment variables that are not committed to source control. This keeps your API keys secret and safe.
Step 3: Implementing Oura API Authentication
We'll use Next.js API routes to handle the OAuth2 flow.
What we're doing
We'll create two API routes: one to redirect the user to Oura's authorization page and another to handle the callback from Oura after the user has granted permission.
Implementation
First, let's create the login route. Create a new file at pages/api/auth/login.js:
// pages/api/auth/login.js
export default function handler(req, res) {
const authUrl = `https://cloud.ouraring.com/oauth/authorize?client_id=${process.env.OURA_CLIENT_ID}&redirect_uri=${process.env.NEXTAUTH_URL}/api/auth/callback&response_type=code&scope=daily`;
res.redirect(authUrl);
}
Now, let's create the callback route at pages/api/auth/callback.js:
// pages/api/auth/callback.js
import { serialize } from 'cookie';
export default async function handler(req, res) {
const { code } = req.query;
if (!code) {
return res.status(400).send('No code provided');
}
const tokenResponse = await fetch('https://api.ouraring.com/oauth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
grant_type: 'authorization_code',
code,
redirect_uri: `${process.env.NEXTAUTH_URL}/api/auth/callback`,
client_id: process.env.OURA_CLIENT_ID,
client_secret: process.env.OURA_CLIENT_SECRET,
}),
});
const tokenData = await tokenResponse.json();
if (tokenData.error) {
return res.status(400).json(tokenData);
}
const cookie = serialize('oura_token', tokenData.access_token, {
httpOnly: true,
secure: process.env.NODE_ENV !== 'development',
maxAge: tokenData.expires_in,
sameSite: 'lax',
path: '/',
});
res.setHeader('Set-Cookie', cookie);
res.redirect('/dashboard');
}```
### How it works
The `/api/auth/login` route simply redirects the user to Oura's authorization page with our `client_id` and `redirect_uri`. Once the user approves, Oura redirects them back to our `/api/auth/callback` route with a temporary `code`.
In the callback, we exchange this `code` for an `access_token`. We then store this `access_token` in an `httpOnly` cookie for secure storage.
## Step 4: Fetching and Displaying Oura Data
Now that we are authenticated, we can fetch the user's data and display it on a dashboard page.
### What we're doing
We'll create a new page at `pages/dashboard.js` that will fetch the Oura data on the server-side using `getServerSideProps` and then pass it to the page component to be rendered. We'll also install the `recharts` library for our charts.
### Implementation
First, install `recharts`:
```bash
npm install recharts
Now, create the pages/dashboard.js file:
// pages/dashboard.js
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
export default function Dashboard({ sleepData, readinessData, activityData }) {
return (
<div>
<h1>Your Oura Wellness Dashboard</h1>
<div style={{ width: '100%', height: 300 }}>
<h2>Sleep Score</h2>
<ResponsiveContainer>
<BarChart data={sleepData}>
<CartesianGrid strokeDasharray: "3 3" />
<XAxis dataKey: "day" />
<YAxis />
<Tooltip />
<Legend />
<Bar dataKey: "score" fill: "#8884d8" />
</BarChart>
</ResponsiveContainer>
</div>
{/* Add similar charts for readiness and activity data */}
</div>
);
}
export async function getServerSideProps(context) {
const { oura_token } = context.req.cookies;
if (!oura_token) {
return {
redirect: {
destination: '/',
permanent: false,
},
};
}
const [sleepResponse, readinessResponse, activityResponse] = await Promise.all([
fetch('https://api.ouraring.com/v2/usercollection/daily_sleep', {
headers: {
'Authorization': `Bearer ${oura_token}`,
},
}),
// ... similar fetch calls for readiness and activity
]);
const sleepJson = await sleepResponse.json();
// ... similar json parsing for readiness and activity
return {
props: {
sleepData: sleepJson.data,
// ... readinessData and activityData
},
};
}
Finally, let's create a simple home page at pages/index.js with a login button:
// pages/index.js
export default function Home() {
return (
<div>
<h1>Welcome to your Wellness Dashboard</h1>
<a href: "/api/auth/login">Login with Oura</a>
</div>
);
}
How it works
In getServerSideProps, we access the oura_token from the cookies. If it doesn't exist, we redirect the user to the homepage to log in. If it does exist, we use it in the Authorization header to make requests to the Oura API endpoints for sleep, readiness, and activity data. This data is then passed as props to our Dashboard component, which uses Recharts to create a simple bar chart.
Putting It All Together
With all the pieces in place, you can now run your application:
npm run dev
Navigate to http://localhost:3000. You should see the login button. Clicking it will take you through the Oura authentication flow, and you'll be redirected to your dashboard with your sleep data visualized!
Security Best Practices
- HttpOnly Cookies: We store the access token in an
httpOnlycookie, which means it cannot be accessed by client-side JavaScript. This helps to mitigate XSS attacks. - Server-Side Data Fetching: By fetching the data in
getServerSideProps, our access token is never exposed to the client's browser.
Conclusion
You've now successfully built a Next.js application that can authenticate with the Oura Ring API, fetch user data, and visualize it in a wellness dashboard. This project serves as a great foundation for building more complex and personalized health and wellness applications.
Resources
Frequently Asked Questions
Q: How do I handle OAuth token expiration when the access token expires after a set time?
A: Implement token refresh logic by storing the refresh token securely and using it to obtain a new access token before expiration. Oura API provides a refresh token in the initial OAuth response. Create a server-side function that checks token expiration and automatically refreshes when needed, keeping the user experience seamless.
Q: Can I fetch historical data beyond what the daily endpoint provides, or am I limited to recent data?
A: The Oura API v2 allows fetching historical data within specific date ranges using query parameters. You can request data for specific start and end dates, enabling you to build historical trend analysis. However, there may be rate limits, so implement caching and batch requests for historical data pulls.
Q: What happens if a user revokes my app's access from their Oura account settings?
A: Your stored access token will become invalid. The API will return 401 errors on subsequent requests. Implement proper error handling to detect this scenario and prompt the user to re-authenticate. You can also implement a token validation endpoint that checks token status before making data requests.
Q: How can I customize the data visualizations beyond the basic bar chart shown in this tutorial?
A: Recharts offers extensive customization options. Explore line charts for time-series trends, area charts for sleep stage distribution, and pie charts for activity breakdowns. You can combine multiple chart types, add custom tooltips, style axes, and implement interactive features like zooming and drilling down into specific data points.
Q: Is it possible to integrate multiple wearable APIs (like Oura + Apple Health) in a single dashboard?
A: Absolutely! Follow similar OAuth2 patterns for each wearable's API. Create a unified data model that normalizes data from different sources, then store and display them together. Consider the varying data schemas and update frequencies of each platform, and build flexible visualizations that can handle diverse health metrics.