Skip to content

Commit d0eca8a

Browse files
committed
new methods on api client to instance a default client with basic params and new methods to authorize requests by headers and url params
1 parent e061015 commit d0eca8a

File tree

9 files changed

+515
-59
lines changed

9 files changed

+515
-59
lines changed

api/client/client.go

Lines changed: 98 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,18 @@ import (
1111
"github.com/simpleauthlink/authapi/token"
1212
)
1313

14-
// DefaultClientTimeout is the default timeout for the client requests. It can
15-
// be overridden in the Config struct.
16-
const DefaultClientTimeout = 30 * time.Second
17-
18-
// DefaultAPIEndpoint is the default API endpoint for the client. It can be
19-
// overridden in the Config struct.
20-
const DefaultAPIEndpoint = "https://api.simpleauth.link"
14+
const (
15+
// DefaultClientTimeout is the default timeout for the client requests. It
16+
// can be overridden in the Config struct.
17+
DefaultClientTimeout = 30 * time.Second
18+
// DefaultAPIEndpoint is the default API endpoint for the client. It can be
19+
// overridden in the Config struct.
20+
DefaultAPIEndpoint = "https://api.simpleauth.link"
21+
DefaultAuthTokenHeader = "X-Auth-Token"
22+
DefaultAuthEmailHeader = "X-Auth-User"
23+
DefaultAuthTokenURLParam = "token"
24+
DefaultAuthEmailURLParam = "user"
25+
)
2126

2227
// Config holds the configuration for the client. It includes the API endpoint,
2328
// application ID, application secret, and the timeout for requests. All fields
@@ -99,7 +104,9 @@ func New(cfg *Config) (*Client, error) {
99104
if err != nil {
100105
return nil, ErrAPIUnavailable
101106
}
102-
defer resp.Body.Close()
107+
defer func() {
108+
_ = resp.Body.Close()
109+
}()
103110
// check if the response is OK
104111
if resp.StatusCode != http.StatusOK {
105112
return nil, ErrAPIUnavailable
@@ -111,6 +118,29 @@ func New(cfg *Config) (*Client, error) {
111118
}, nil
112119
}
113120

121+
// Default method creates a new Client instance with the default configuration
122+
// and the provided application ID and secret. Both inputs are required. The
123+
// application ID is expected as a string to prevent the user from converting
124+
// it.
125+
func Default(strAppID, appSecret string) (*Client, error) {
126+
if appSecret == "" {
127+
return nil, ErrInvalidAppSecret
128+
}
129+
if strAppID == "" {
130+
return nil, ErrInvalidAppID
131+
}
132+
appID := new(token.AppID).SetString(strAppID)
133+
if !new(token.App).SetID(appID).Valid(nil) {
134+
return nil, ErrInvalidAppID
135+
}
136+
return New(&Config{
137+
APIEndpoint: DefaultAPIEndpoint,
138+
AppID: appID,
139+
AppSecret: appSecret,
140+
Timeout: DefaultClientTimeout,
141+
})
142+
}
143+
114144
// NewAppID method creates a new AppID with the provided name, redirect URI,
115145
// secret, and session duration. It requires the client configuration to be
116146
// valid, including the application ID and secret. The name, redirect URI,
@@ -191,7 +221,9 @@ func (c *Client) RequestToken(email string) error {
191221
if err != nil {
192222
return ErrAPIUnavailable
193223
}
194-
defer res.Body.Close()
224+
defer func() {
225+
_ = res.Body.Close()
226+
}()
195227
// check if the response is OK
196228
if res.StatusCode != http.StatusOK {
197229
return ErrRequestToken
@@ -243,6 +275,63 @@ func (c *Client) VerifyToken(token *token.Token, email string) (bool, time.Time,
243275
return resData.Valid, resData.Expiration, nil
244276
}
245277

278+
// AuthorizedRequestURLParams method checks if the request is authorized by
279+
// verifying the token and email from the URL params of the request using the
280+
// current client instance. It receives the request to check, and returns the
281+
// user email in the request and a boolean that indicates if the token in the
282+
// request is currently valid. If the client configuration is invalid, the
283+
// request does not contains the required information or the validation fails,
284+
// it returns an error.
285+
func (c *Client) AuthorizedRequestURLParams(r *http.Request) (string, bool, error) {
286+
if err := c.config.Validate(true); err != nil {
287+
return "", false, err
288+
}
289+
params, err := url.ParseQuery(r.URL.RawQuery)
290+
if err != nil {
291+
// map it to your sentinel
292+
return "", false, ErrMissingAuthURLParams
293+
}
294+
// get the strToken and email from the request headers
295+
strToken, _ := url.QueryUnescape(params.Get(DefaultAuthTokenURLParam))
296+
userEmail, _ := url.QueryUnescape(params.Get(DefaultAuthEmailURLParam))
297+
// check if the token and email are valid
298+
if strToken == "" || userEmail == "" {
299+
return "", false, ErrMissingAuthURLParams
300+
}
301+
userToken := new(token.Token).SetString(strToken)
302+
valid, _, err := c.VerifyToken(userToken, userEmail)
303+
if err != nil {
304+
return "", false, err
305+
}
306+
return userEmail, valid, nil
307+
}
308+
309+
// AuthorizedRequestHeaders method checks if the request is authorized by
310+
// verifying the token and email from the headers of the request using the
311+
// current client instance. It receives the request to check, and returns the
312+
// user email in the request and a boolean that indicates if the token in the
313+
// request is currently valid. If the client configuration is invalid, the
314+
// request does not contains the required information or the validation fails,
315+
// it returns an error.
316+
func (c *Client) AuthorizedRequestHeaders(r *http.Request) (string, bool, error) {
317+
if err := c.config.Validate(true); err != nil {
318+
return "", false, err
319+
}
320+
// get the strToken and email from the request headers
321+
strToken := r.Header.Get(DefaultAuthTokenHeader)
322+
userEmail := r.Header.Get(DefaultAuthEmailHeader)
323+
// check if the token and email are valid
324+
if strToken == "" || userEmail == "" {
325+
return "", false, ErrMissingAuthHeaders
326+
}
327+
userToken := new(token.Token).SetString(strToken)
328+
valid, _, err := c.VerifyToken(userToken, userEmail)
329+
if err != nil {
330+
return "", false, err
331+
}
332+
return userEmail, valid, nil
333+
}
334+
246335
// req internal method creates a new HTTP request with the provided config,
247336
// method, path, and data. It validates the configuration and sets the
248337
// necessary headers. If the data is provided, it writes the JSON data to the

0 commit comments

Comments
 (0)