@@ -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