Skip to content

Commit dd6918b

Browse files
author
Chris Stasonis
committed
Initial commit
0 parents  commit dd6918b

File tree

12 files changed

+409
-0
lines changed

12 files changed

+409
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
target

README.MD

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#Fitbit OAuth Spring Boot Demo
2+
3+
This app deals with the boilerplate code of using the Fitbit API with Spring Boot, authenticating via OAuth and making a simple API call. It is meant as a starting point for more robust applications and a demonstration of some of the basic concepts of the API. Java 8 is preferred, though
4+
5+
[Installing a JDK](https://docs.oracle.com/javase/8/docs/technotes/guides/install/install_overview.html)
6+
[Read More About the Fitbit API](https://dev.fitbit.com/docs/)
7+
8+
##Prerequisites
9+
This document assumes you have a JDK and maven installed. A tutorial for installing these is out of scope for this project, but there are many resources to instruct you on how to do so.
10+
11+
[Installing Apache Maven](https://maven.apache.org/install.html)
12+
13+
## Developing Your Own App
14+
15+
First fork this repo
16+
17+
Then create a [Fitbit App Config](https://dev.fitbit.com/apps/new).
18+
19+
This is the config I used while developing. Your app may not need read/write access.
20+
21+
![This is the config I used](screenshots/fitbit_oauth_settings.png)
22+
23+
Once you have setup your app you need to put the client ID and client secret into the application config. You should be able to find both of these on the [manage apps page](https://dev.fitbit.com/apps). These values should be placed in src/main/resources/application.yml. No quotes are required around these values, simply paste them over the placeholders.
24+
25+
```
26+
security:
27+
oauth2:
28+
client:
29+
clientId: YOUR_CLIENT_ID_HERE
30+
clientSecret: YOUR_CLIENT_SECRET_HERE
31+
accessTokenUri: https://api.fitbit.com/oauth2/token
32+
userAuthorizationUri: https://www.fitbit.com/oauth2/authorize
33+
tokenName: oauth_token
34+
authenticationScheme: header
35+
clientAuthenticationScheme: header
36+
scope: "activity heartrate location nutrition profile settings sleep social weight"
37+
resource:
38+
userInfoUri: https://api.fitbit.com/1/user/-/profile.json
39+
fitbit:
40+
api:
41+
resource:
42+
activitiesUri: https://api.fitbit.com/1/user/-/activities.json
43+
44+
logging:
45+
level:
46+
org.springframework.security: TRACE
47+
```
48+
49+
You should decide on the OAuth scopes for your project. Specifically, define what data your app will
50+
be accessing from people's Fitbit accounts. These are also defined in application.yml. By default this file requests every scope, but you should remove those you do not need
51+
52+
[Read more about OAuth Scopes](https://dev.fitbit.com/docs/oauth2/)
53+
54+
Once you have saved you changes starting the app is easy. Simply run
55+
```
56+
mvn spring-boot:run
57+
```
58+
59+
After a moment your app should be started and you can go to [http://localhost:8080](http://localhost:8080) and follow the login flow.
60+
61+
The app as written will only access your fitbit profile to demonstrate OAuth working.

pom.xml

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<groupId>com.example</groupId>
7+
<artifactId>fibit-oauth</artifactId>
8+
<version>0.0.1-SNAPSHOT</version>
9+
<packaging>jar</packaging>
10+
11+
<name>fitbit-oauth</name>
12+
<description>Demo project for Fitbit API</description>
13+
14+
<parent>
15+
<groupId>org.springframework.boot</groupId>
16+
<artifactId>spring-boot-starter-parent</artifactId>
17+
<version>1.4.0.RELEASE</version>
18+
<relativePath /> <!-- lookup parent from repository -->
19+
</parent>
20+
21+
<properties>
22+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
23+
<java.version>1.8</java.version>
24+
</properties>
25+
26+
<dependencies>
27+
<dependency>
28+
<groupId>org.springframework.boot</groupId>
29+
<artifactId>spring-boot-starter-actuator</artifactId>
30+
</dependency>
31+
<dependency>
32+
<groupId>org.springframework.boot</groupId>
33+
<artifactId>spring-boot-starter-security</artifactId>
34+
</dependency>
35+
<dependency>
36+
<groupId>org.springframework.boot</groupId>
37+
<artifactId>spring-boot-starter-web</artifactId>
38+
</dependency>
39+
<dependency>
40+
<groupId>org.springframework.security.oauth</groupId>
41+
<artifactId>spring-security-oauth2</artifactId>
42+
</dependency>
43+
<dependency>
44+
<groupId>org.webjars</groupId>
45+
<artifactId>angularjs</artifactId>
46+
<version>1.4.3</version>
47+
</dependency>
48+
<dependency>
49+
<groupId>org.webjars</groupId>
50+
<artifactId>jquery</artifactId>
51+
<version>2.1.1</version>
52+
</dependency>
53+
<dependency>
54+
<groupId>org.webjars</groupId>
55+
<artifactId>bootstrap</artifactId>
56+
<version>3.2.0</version>
57+
</dependency>
58+
<dependency>
59+
<groupId>org.webjars</groupId>
60+
<artifactId>webjars-locator</artifactId>
61+
</dependency>
62+
63+
<dependency>
64+
<groupId>org.springframework.boot</groupId>
65+
<artifactId>spring-boot-starter-test</artifactId>
66+
<scope>test</scope>
67+
</dependency>
68+
69+
<dependency>
70+
<groupId>org.json</groupId>
71+
<artifactId>json</artifactId>
72+
<version>20160810</version>
73+
</dependency>
74+
75+
</dependencies>
76+
77+
<build>
78+
<plugins>
79+
<plugin>
80+
<groupId>org.springframework.boot</groupId>
81+
<artifactId>spring-boot-maven-plugin</artifactId>
82+
</plugin>
83+
</plugins>
84+
</build>
85+
86+
</project>

screenshots/fitbit_oauth_settings.png

148 KB
Loading
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Copyright 2012-2015 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.fitbit;
17+
18+
import com.fitbit.model.Activity;
19+
import com.fitbit.model.LifetimeActivity;
20+
import org.springframework.beans.factory.annotation.Autowired;
21+
import org.springframework.beans.factory.annotation.Value;
22+
import org.springframework.boot.SpringApplication;
23+
import org.springframework.boot.autoconfigure.SpringBootApplication;
24+
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
25+
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
26+
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
27+
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
28+
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
29+
import org.springframework.web.bind.annotation.RequestMapping;
30+
import org.springframework.web.bind.annotation.RestController;
31+
32+
import java.security.Principal;
33+
34+
@SpringBootApplication
35+
@EnableOAuth2Sso
36+
@RestController
37+
@EnableWebSecurity
38+
public class FitbitOAuthExample extends WebSecurityConfigurerAdapter {
39+
40+
@Autowired
41+
OAuth2RestTemplate fitbitOAuthRestTemplate;
42+
43+
@Value("${fitbit.api.resource.activitiesUri}")
44+
String fitbitActivitiesUri;
45+
46+
@RequestMapping("/lifetime-activity")
47+
public LifetimeActivity lifetimeActivity() {
48+
LifetimeActivity lifetimeActivity;
49+
50+
try {
51+
Activity a = fitbitOAuthRestTemplate.getForObject(fitbitActivitiesUri, Activity.class);
52+
lifetimeActivity = a.getLifetime().getTotal();
53+
}
54+
catch(Exception e) {
55+
lifetimeActivity = new LifetimeActivity();
56+
}
57+
58+
return lifetimeActivity;
59+
}
60+
61+
@RequestMapping("/user")
62+
public Principal user(Principal principal) {
63+
return principal;
64+
}
65+
66+
@Override
67+
protected void configure(HttpSecurity http) throws Exception {
68+
http.antMatcher("/**").authorizeRequests().antMatchers("/", "/login**", "/webjars/**").permitAll().anyRequest()
69+
.authenticated();
70+
}
71+
72+
public static void main(String[] args) {
73+
SpringApplication.run(FitbitOAuthExample.class, args);
74+
}
75+
76+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.fitbit.model;
2+
3+
public class Activity {
4+
5+
private LifetimeActivities lifetime;
6+
7+
public LifetimeActivities getLifetime() {
8+
return lifetime;
9+
}
10+
11+
public void setLifetime(LifetimeActivities lifetime) {
12+
this.lifetime = lifetime;
13+
}
14+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.fitbit.model;
2+
3+
import org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoRestTemplateFactory;
4+
import org.springframework.context.annotation.Bean;
5+
import org.springframework.context.annotation.Configuration;
6+
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
7+
8+
@Configuration
9+
public class FitbitAPIConfiguration {
10+
11+
@Bean
12+
OAuth2RestTemplate fitbitOAuthRestTemplate(UserInfoRestTemplateFactory uir) {
13+
return uir.getUserInfoRestTemplate();
14+
}
15+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.fitbit.model;
2+
3+
public class LifetimeActivities {
4+
private LifetimeActivity total;
5+
6+
public LifetimeActivity getTotal() {
7+
return total;
8+
}
9+
10+
public void setTotal(LifetimeActivity total) {
11+
this.total = total;
12+
}
13+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.fitbit.model;
2+
3+
public class LifetimeActivity {
4+
5+
private int caloriesOut = 0;
6+
private float distance = 0;
7+
private int floors = 0;
8+
private int steps = 0;
9+
10+
public int getCaloriesOut() {
11+
return caloriesOut;
12+
}
13+
14+
public void setCaloriesOut(int caloriesOut) {
15+
this.caloriesOut = caloriesOut;
16+
}
17+
18+
public float getDistance() {
19+
return distance;
20+
}
21+
22+
public void setDistance(float distance) {
23+
this.distance = distance;
24+
}
25+
26+
public int getFloors() {
27+
return floors;
28+
}
29+
30+
public void setFloors(int floors) {
31+
this.floors = floors;
32+
}
33+
34+
public int getSteps() {
35+
return steps;
36+
}
37+
38+
public void setSteps(int steps) {
39+
this.steps = steps;
40+
}
41+
}

src/main/resources/application.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
security:
2+
oauth2:
3+
client:
4+
clientId: YOUR_CLIENT_ID_HERE
5+
clientSecret: YOUR_CLIENT_SECRET_HERE
6+
accessTokenUri: https://api.fitbit.com/oauth2/token
7+
userAuthorizationUri: https://www.fitbit.com/oauth2/authorize
8+
tokenName: oauth_token
9+
authenticationScheme: header
10+
clientAuthenticationScheme: header
11+
scope: "activity heartrate location nutrition profile settings sleep social weight"
12+
resource:
13+
userInfoUri: https://api.fitbit.com/1/user/-/profile.json
14+
fitbit:
15+
api:
16+
resource:
17+
activitiesUri: https://api.fitbit.com/1/user/-/activities.json
18+
19+
logging:
20+
level:
21+
org.springframework.security: TRACE

src/main/resources/static/index.html

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
6+
<title>Demo</title>
7+
<meta name="description" content="" />
8+
<meta name="viewport" content="width=device-width" />
9+
<base href="/" />
10+
<link rel="stylesheet" type="text/css"
11+
href="/webjars/bootstrap/css/bootstrap.min.css" />
12+
<script type="text/javascript" src="/webjars/jquery/jquery.min.js"></script>
13+
<script type="text/javascript"
14+
src="/webjars/bootstrap/js/bootstrap.min.js"></script>
15+
</head>
16+
<body ng-app="app" ng-controller="home as home">
17+
<h1>Login</h1>
18+
<div class="container" ng-show="!home.authenticated">
19+
With Fitbit: <a href="/login">click here</a>
20+
</div>
21+
<div class="container" ng-show="home.authenticated">
22+
Logged in as: <span ng-bind="home.user"></span><br />
23+
Lifetime Steps: <span ng-bind="home.lifetimeSteps"></span><br />
24+
Lifetime Distance: <span ng-bind="home.lifetimeDistance"></span><br />
25+
Lifetime Floors: <span ng-bind="home.lifetimeFloors"></span><br />
26+
</div>
27+
<script type="text/javascript" src="/webjars/angularjs/angular.min.js"></script>
28+
<script type="text/javascript">
29+
angular.module("app", []).controller("home", function($http) {
30+
var self = this;
31+
32+
$http.get("/user").success(function(data) {
33+
self.user = data.userAuthentication.details.user.fullName;
34+
self.authenticated = true;
35+
}).error(function() {
36+
self.user = "N/A";
37+
self.authenticated = false;
38+
});
39+
40+
$http.get("/lifetime-activity").success(function(data) {
41+
self.lifetimeSteps = data.steps.toLocaleString();
42+
self.lifetimeFloors = data.floors.toLocaleString();
43+
self.lifetimeDistance = data.distance.toLocaleString();
44+
}).error(function() {
45+
self.lifetimeSteps = "N/A";
46+
});
47+
});
48+
</script>
49+
</body>
50+
</html>

0 commit comments

Comments
 (0)