-
Notifications
You must be signed in to change notification settings - Fork 0
/
facebook.coffee
176 lines (122 loc) · 4.9 KB
/
facebook.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
_ = require "underscore"
fbgraph = require "fbgraph"
oauth = require "./auth"
# initial facebook class object which should pave the way for the rest of this circus
facebook = (opts) ->
# collection/model to use for oauth
@model = null
# prefix for initial route listening
@prefix = "/auth/facebook"
# add an option to set your logout prefix
@logout_url = @prefix + "/logout"
# redirect uri for facebook oauth
@redirect_uri = "/callback"
# callback_url is for validating your route
# however when i designed this i forked my brain
# for some reason, this will change -- or be gone
# completely.
@callback_url = "/callback"
# your facebook app id
@client_id = null
# custom key name for either `req` or `res.locals`
@key = null
# your facebook app secret
@client_secret = null
# define permissions `scope`
@scope = "email, publish_actions"
@strategy = null
if opts? then _.extend @, opts
@_col = @key + "_id"
_logout = @prefix + @logout_url
@logout_url = _logout
self = @
# oauth through `fbgraph`
@oauth = (req, res, next) ->
# evaluate what url to pass
if not req.query.code
# start to build our `oauthurl`
oauth_uri = fbgraph.getOauthUrl
client_id: self.client_id
redirect_uri: self.redirect_uri
scope: self.scope
# check to make sure we're error free!!
if not req.query.error
# redirect to the oauth uri
res.redirect oauth_uri
else
# we've got an error, let's do something with it
next "Sorry, facebook has reported an error: #{req.query.error}", null
else
# build our oauth_callback object so we can get some access to facebook
oauth_callback =
client_id: self.client_id
client_secret: self.client_secret
redirect_uri: self.redirect_uri
code: req.query.code
# do fbgraph.authorize to get us in the field!
fbgraph.authorize oauth_callback, (err, response) ->
return if err? then next err, null
# store our access token so we can use it for awhile
if response.access_token? then fbgraph.setAccessToken response.access_token
# no user found, maybe someone's being tricky?
# else next "Whoops! It looks like Facebook didn't give us a real answer.", null
# this will do a facebook graph call to get
# consumable user data..
fbgraph.get "me", (err, response) ->
return if err? then next err, null
# pass this response to a callback
if response?
if self.strategy == null
req[self.key] = res.locals[self.key] = response
next null, response
else self.strategy response, (err, saved) ->
return if err? then next err, null
if saved?
req[self.key] = res.locals[self.key] = saved
next null, saved
else
fn "Facebook lost your token while redirecting back here, please try again.", null
# auth functions, `serialize, deserialize, and ensureAuthenticated` reside
@auth = new oauth self.model, self.key
@authenticate = (req, res) ->
self.auth.serialize req[self.key], (err, id) ->
# set session to the `optin_id` so we can `pseudo` serialize
req.session[self._col] = id
# send optin to their referring page
res.redirect "back"
# build out a way to logout -- defaults to
# `/auth/facebook/logout` it'll have an option though
@logout = (req, res) ->
# build a `route` for logging out / ie deleting your session
# easily enough to reproduce yourself if you so choose
if req.session.hasOwnProperty(self._col)
delete req.session[self._col]
res.redirect "/"
else
# back is a fancy fallback that will look for `referer` but
# give the home page if not found, safely.
res.redirect "back"
@mount = (app) ->
# build initial route point with oauth handler
app.get self.prefix, self.oauth
# we're gonna do something fancy here if there isn't a strategy --
# we're going to store the whole shabang in to our session
if self.strategy == null
app.get self.prefix + self.callback_url, self.oauth, self.authenticate
else
app.get self.prefix + self.callback_url, self.oauth, self.authenticate, self.strategy
# give access to `/logout`
app.get self.prefix + self.logout_url, self.logout
# persistent session
@session = (req, res, next) ->
# if the session exists, lets deserialize it so we can play with it in our
# application
if req.session.hasOwnProperty(self._col)
# run those traps!
self.auth.deserialize req.session[self._col], (err, deserialized) ->
return if err? then next err, null
if deserialized? then req[self.key] = res.locals[self.key] = deserialized
next()
else next()
@
module.exports = facebook