Skip to content

Commit 3fed412

Browse files
committed
oauth2 example
1 parent eeb0326 commit 3fed412

File tree

3 files changed

+169
-0
lines changed

3 files changed

+169
-0
lines changed
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package io.vertx.example.web.oauth2;
2+
3+
import io.vertx.core.AbstractVerticle;
4+
import io.vertx.core.json.JsonArray;
5+
import io.vertx.core.json.JsonObject;
6+
import io.vertx.example.util.Runner;
7+
import io.vertx.ext.auth.oauth2.AccessToken;
8+
import io.vertx.ext.auth.oauth2.OAuth2Auth;
9+
import io.vertx.ext.auth.oauth2.providers.GithubAuth;
10+
import io.vertx.ext.web.Router;
11+
import io.vertx.ext.web.RoutingContext;
12+
import io.vertx.ext.web.handler.*;
13+
import io.vertx.ext.web.sstore.LocalSessionStore;
14+
import io.vertx.ext.web.templ.HandlebarsTemplateEngine;
15+
16+
/*
17+
* @author <a href="mailto:[email protected]">Paulo Lopes</a>
18+
*/
19+
public class Server extends AbstractVerticle {
20+
21+
private static final String CLIENT_ID = System.getenv("GH_BASIC_CLIENT_ID");
22+
private static final String CLIENT_SECRET = System.getenv("GH_BASIC_SECRET_ID");
23+
24+
// In order to use a template we first need to create an engine
25+
private final HandlebarsTemplateEngine engine = HandlebarsTemplateEngine.create();
26+
27+
// Convenience method so you can run it in your IDE
28+
public static void main(String[] args) {
29+
Runner.runExample(Server.class);
30+
}
31+
32+
private boolean isAuthenticated(RoutingContext ctx) {
33+
return ctx.user() != null;
34+
}
35+
36+
private void authenticate(RoutingContext ctx) {
37+
// we pass the client id to the template
38+
ctx.put("client_id", CLIENT_ID);
39+
// and now delegate to the engine to render it.
40+
engine.render(ctx, "views", "/index.hbs", res -> {
41+
if (res.succeeded()) {
42+
ctx.response()
43+
.putHeader("Content-Type", "text/html")
44+
.end(res.result());
45+
} else {
46+
ctx.fail(res.cause());
47+
}
48+
});
49+
}
50+
51+
@Override
52+
public void start() throws Exception {
53+
// To simplify the development of the web components we use a Router to route all HTTP requests
54+
// to organize our code in a reusable way.
55+
final Router router = Router.router(vertx);
56+
// We need cookies, sessions and request bodies
57+
router.route().handler(CookieHandler.create());
58+
router.route().handler(BodyHandler.create());
59+
router.route().handler(SessionHandler.create(LocalSessionStore.create(vertx)));
60+
// Simple auth service which uses a GitHub to authenticate the user
61+
OAuth2Auth authProvider = GithubAuth.create(vertx, CLIENT_ID, CLIENT_SECRET);
62+
// We need a user session handler too to make sure the user is stored in the session between requests
63+
router.route().handler(UserSessionHandler.create(authProvider));
64+
// Entry point to the application, this will render a custom template.
65+
router.get("/").handler(ctx -> {
66+
if (!isAuthenticated(ctx)) {
67+
authenticate(ctx);
68+
} else {
69+
AccessToken user = (AccessToken) ctx.user();
70+
71+
user.userInfo(res -> {
72+
if (res.failed()) {
73+
res.cause().printStackTrace();
74+
// request didn't succeed because the token was revoked so we
75+
// invalidate the token stored in the session and render the
76+
// index page so that the user can start the OAuth flow again
77+
ctx.session().destroy();
78+
authenticate(ctx);
79+
} else {
80+
// the request succeeded, so we check the list of current scopes
81+
JsonArray scopes = new JsonArray();
82+
JsonObject userInfo = res.result();
83+
84+
if (userInfo.containsKey("X-OAuth-Scopes")) {
85+
for (String scope : userInfo.getString("X-OAuth-Scopes").split(", ")) {
86+
scopes.add(scope);
87+
}
88+
}
89+
90+
if (scopes.contains("user:email")) {
91+
// fetch the user emails from the github API
92+
user.fetch("https://api.github.com/user/emails", res2 -> {
93+
if (res2.failed()) {
94+
res2.cause().printStackTrace();
95+
// request didn't succeed because the token was revoked so we
96+
// invalidate the token stored in the session and render the
97+
// index page so that the user can start the OAuth flow again
98+
ctx.session().destroy();
99+
authenticate(ctx);
100+
} else {
101+
userInfo.put("private_emails", res2.result().jsonArray());
102+
103+
// we pass the client id to the template
104+
ctx.put("userInfo", userInfo);
105+
106+
// and now delegate to the engine to render it.
107+
engine.render(ctx, "views", "/advanced.hbs", res3 -> {
108+
if (res3.succeeded()) {
109+
ctx.response()
110+
.putHeader("Content-Type", "text/html")
111+
.end(res3.result());
112+
} else {
113+
ctx.fail(res3.cause());
114+
}
115+
});
116+
}
117+
});
118+
}
119+
120+
}
121+
});
122+
}
123+
});
124+
// the callback url
125+
OAuth2AuthHandler oauth2Handler = OAuth2AuthHandler.create(authProvider, "http://localhost:8080/callback");
126+
oauth2Handler.setupCallback(router.route("/callback"));
127+
128+
vertx.createHttpServer().requestHandler(router::accept).listen(8080);
129+
}
130+
}
131+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<html>
2+
<head>
3+
</head>
4+
<body>
5+
<p>Well, well, well, {{userInfo.login}}!</p>
6+
<p>
7+
{{#if userInfo.email}} It looks like your public email address is {{userInfo.email}}.
8+
{{else}} It looks like you don't have a public email. That's cool.
9+
{{/if}}
10+
</p>
11+
<p>
12+
{{#if userInfo.private_emails}}
13+
With your permission, we were also able to dig up your private email addresses:
14+
{{#each userInfo.private_emails}}
15+
{{email}},
16+
{{/each}}
17+
{{else}}
18+
Also, you're a bit secretive about your private email addresses.
19+
{{/if}}
20+
</p>
21+
</body>
22+
</html>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<html>
2+
<head>
3+
</head>
4+
<body>
5+
<p>
6+
Well, hello there!
7+
</p>
8+
<p>
9+
We're going to now talk to the GitHub API. Ready?
10+
<a href="https://github.com/login/oauth/authorize?scope=user:email&client_id={{client_id}}">Click here</a> to begin!</a>
11+
</p>
12+
<p>
13+
If that link doesn't work, remember to provide your own <a href="https://github.com/settings/applications/new">Client ID</a>!
14+
</p>
15+
</body>
16+
</html>

0 commit comments

Comments
 (0)