How to get authenticate with the squareup using backend golang? - security

In sqaureup application Aplication_name in oauth option there is a redirect url Which will redirect a given url with the QueryString code. While I'm hitting https://connect.squareup.com/oauth2/authorize?client_id=YOUR_CLIENT_ID this url in the browser then it will redirect me to a given url in oauth with attached code. And then to take a access_token you have to give a POST request to given url https://connect.squareup.com/oauth2/token with the body
{
"client_id": "YOUR_APPLICATION_ID",
"client_secret": "YOUR_APPLICATION_SECRET",
"code": "M-Q7k-N0Emx_3cBqwbVLTQ",
"redirect_uri": "YOUR_REDIRECT_URI"
}
I do it same and send By method POST to this url with json data but it will gives me the error:-
{
"message": "Not Authorized",
"type": "service.not_authorized"
}
The Golang Code I'm using for this is :-
func Token(c *gin.Context) {
code := c.Query("code") // code be something like:-sq0cgp-wLVQt5HOLfug6xiVdmCDCf
splitCode := strings.Split(code, "-")
token := models.PostToken{
ClientID: "YOUR_APPLICATION_ID",
ClientSecret: "YOUR_APPLICATION_SECRET",
Code: splitCode[1],
RedirectUri: c.Request.Host + c.Request.URL.RequestURI(),
}
bindData, err := json.Marshal(token)
if err != nil {
panic(err)
}
var jsonStr = []byte(string(bindData))
url := "https://connect.squareup.com/oauth2/token"
req, err := http.Post(url, "application/json", bytes.NewBuffer(jsonStr))
fmt.Println(req, err)
}
Models struct:-
type PostToken struct {
ClientID string `json:"client_id" bson:"client_id"`
ClientSecret string `json:"client_secret" bson:"client_secret"`
Code string `json:"code" bson:"code"`
RedirectUri string `json:"redirect_uri" bson:"redirect_uri"`
}

You have to do some points I mentioned:-
First check your application Id.
In second parameter ClientSecret you have to use Oauth Application Secret key Which you will got from the application dashboard -> Oauth option.
In Code you don't have send the split code send simple string code value which your getting in the variable name code.
Fourth parameter is optional as the documentation says here.
Then you will got what you want :D.

Related

Mobile app performing an HTTP Post to Azure Function using Bearer Token and Function Key returns Unauthorized

I'm using a mobile app and am receiving an Unauthorized response when attempting to post to an Azure Function and providing a function key.
Error:
StatusCode: 401, ReasonPhrase: 'Unauthorized'
Code:
let postToAsync (baseAddress:string) (resource:string) (payload:Object) =
async {
let tokenSource = new CancellationTokenSource(TimeSpan(0,0,30));
let token = tokenSource.Token;
try
let tokens = resource.Split("?code=")
let functionKey = tokens.[1]
use client = httpClient baseAddress
client.DefaultRequestHeaders.Add("x-functions-key", functionKey)
client.DefaultRequestHeaders.Accept.Add(MediaTypeWithQualityHeaderValue("application/json"))
let json = JsonConvert.SerializeObject(payload)
let content = new StringContent(json, Encoding.UTF8, "application/json")
let! response = client.PostAsync(resource.Replace($"?code={functionKey}",""), content, token) |> Async.AwaitTask
Debug.WriteLine $"\n\n{baseAddress}{resource}\nSuccess: {response.IsSuccessStatusCode}\n\n"
return response
with ex -> ...
} |> Async.StartAsTask
Note:
My Azure Function's AuthorizationLevel is set to Function.
I can call the function successfully when I publish it manually from Visual Studio.
However, when I deploy the function using Pulumi, I receive an Unauthorized response. I believe this is because Pulumi constrains me to add access policies for each Function App.
Versioning:
<TargetFramework>net6.0</TargetFramework>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
oauth2/v2.0:
I think the following link provides a clue to why I'm observing the issue. However, I still don't know how to resolve it.
Connectivity
I launched Log Stream and observed that the URL is correct:
Access Control:
Please note that the difference between the Function App that I created without using Pulumi, which lets me post successfully, versus the Function App that was generated using Pulumi, is an Access Policy per Function App with Pulumi.
public static class AccessPolicies
{
public static void Build(string policyName, string functionName, Dictionary<string, CustomResource> registry)
{
var resourceGroup = registry[nameof(ResourceGroup)] as ResourceGroup;
var keyVault = registry[nameof(KeyVault)] as KeyVault;
var functionApp = registry[functionName] as FunctionApp;
var result = new AccessPolicy(policyName, new AccessPolicyArgs {
KeyVaultId = keyVault.Id,
TenantId = TenantId.Value,
ObjectId = functionApp.Identity.Apply(v => v.PrincipalId ?? "11111111-1111-1111-1111-111111111111"),
KeyPermissions = new[] { "Get", },
SecretPermissions = new[] { "Get", },
});
registry.Add($"{policyName}-{functionName}", result);
}
}
}
I tried to reproduce the same in my environment via Postman and got below results:
I have one function app with http function named srifunction like below:
I generated one bearer token with same scope as you like below:
POST https://login.microsoftonline.com/<tenantID>/oauth2/v2.0/token
grant_type:client_credentials
client_id: <appID>
client_secret: <secret_value>
scope: https://management.azure.com/.default
Response:
When I used the above token to call function, I got 401 Unauthorized error same as you like below:
POST https://<funcappName>.azurewebsites.net/api/<function_name>
Authorization: Bearer <token>
If you pass function key in token value, you will still get 401 Unauthorized error like below:
POST https://<funcappName>.azurewebsites.net/api/<function_name>
Authorization: Bearer <function key>
To call function using function key, you need to include key value
in x-functions-key header instead of Bearer token.
When I included the above header, I am able to call the function successfully like below:
POST https://<funcappName>.azurewebsites.net/api/<function_name>
x-functions-key: <function key>

Swift Auth0 access code results in unauthorized access but nothing in Auth0 logs

I have a nestJS backend protected with Auth0. I am able to successfully access the backend from react-admin by including the access token in the authorization header (Authorization: Bearer ACCESS_TOKEN)
However, I seem to have an issue when trying to access the same backend from a Swift iOS app. I have followed the Auth0 tutorials and am able to confirm successful user login and access to user profile. However, when I try to make a request to the nestJS backend, I receive a 401 Unauthorized error. Interestingly, nothing is recorded in the Auth0 logs.
Link to Auth0 tutorial: https://auth0.com/docs/quickstart/native/ios-swift/04-calling-apis
let path = "\(baseURL)\(endpoint.rawValue)"
guard let url = URL(string: path)
else { preconditionFailure("Bad URL") }
var headers: [String:String] = [:]
headers["Content-Type"] = "application/json"
// if access token is set then set Authorization headers
if (accessToken != nil) {
headers["Authorization"] = "Bearer \(accessToken!)"
print("Bearer \(accessToken!)")
}
var request = URLRequest(url: url)
request.httpMethod = "\(method)"
request.allHTTPHeaderFields = headers
// check if body exists
if (body != nil) {
request.httpBody = body!
}
let dataTask = URLSession.shared.dataTask(with: request) {
(data, response, error) in
guard error == nil
else { completion(.failure(.serverError)); return }
do {
guard let data = data
else { completion(.failure(.serverError)); return }
guard let object : [[String: AnyObject]] = try JSONSerialization.object(with: data) as? [[String: AnyObject]]
else {
print("Unable to convert from data")
return
}
guard let json = try? JSONSerialization.data(withJSONObject: object, options: .prettyPrinted)
else {
print("Unable to prettify")
return
}
guard let jsonString = String(data: json, encoding: .utf8)
else {
print("Unable to convert to string")
return
}
print("JSON: \(jsonString)")
completion(Result.success(object))
} catch {
completion(Result.failure(.parsingError))
}
}
dataTask.resume()
baseURL is a string that points to my nestJS backend.
endpoint is an enum of endpoints, for example \user
Using Proxyman I am able to confirm that the endpoint is hit with the correct headers. Screenshot below.
Additionally, using postman I am able to successfully login and also make a get request to protected data. Screenshot below.
Any ideas to what might be the cause? Let me know if I should add any additional details.
UPDATE
I decoded the successful (react-admin) and unsuccessful (iOS) JWT tokens and noticed the following differences:
aud in the successful JWT contains an array of audiences that include the API registerd on Auth0 as well as an auth0 endpoint https://xxxxx.us.auth0.com/userinfo
azp is only present in the successful JWT and contains my clientID
aud in the unsuccessful token contains the clientID
scope and permissions is missing from unsuccessful token.
Ps. also posted on Auth0 Community
https://community.auth0.com/t/access-token-when-obtained-from-ios-results-in-401-unauthorized-while-from-react-admin-is-ok/71115
The problem was that audience was set when requesting access tokens from the react-admin, while I did not include this in the swift login implementation.
Decoding the JWT on jwt.io and the following thread lead to this conclusion.
https://community.auth0.com/t/access-token-too-short-jwt-malformed/9169/11?u=kennethphough
Adding the audience in the following code resulted in the correct jwt being returned and successful access to backend.
Auth0
.authentication()
.login(
usernameOrEmail: self.email,
password: self.password,
realm: "Username-Password-Authentication",
audience: "<YOUR_AUDIENCE>", // <- This is what I forgot
scope: "openid profile email"
)

How to access already authenticated user from web application behind Google Identity Aware Proxy?

I have a web application which sits behind Google's Identity Aware Proxy (IAP). IAP authenticates the user before forwarding to my web application. How can I access the already authenticated user from my web application?
In Getting the user's identity it states there are X-Goog-Authenticated-User-Email and X-Goog-Authenticated-User-Id headers. However, I don't see those in the response headers:
accept-ranges: bytes
alt-svc: clear
content-length: 14961
content-type: text/html; charset=utf-8
date: Thu, 01 Apr 2021 15:21:01 GMT
last-modified: Wed, 31 Mar 2021 19:34:58 GMT
via: 1.1 google
I do see a few cookies:
GCP_IAAP_AUTH_TOKEN_xxx
GCP_IAP_UID
GCP_IAP_XSRF_NONCE_xxx
For example, I want to be able to show their name and avatar photo in my web app to show that they are authenticated and logged in. I know that info is available via Google's OAuth2 struct, but how can I get that from IAP?
I was able to get this working after #JohnHanley mentioned that the headers only show up when running behind IAP. You cannot see them during local development.
I could see them after deploying a simple, temporary, /headers route which loops through them and writes to the ResponseWriter. X-Goog-Authenticated-User-Id, X-Goog-Authenticated-User-Email and X-Goog-Iap-Jwt-Assertion.
import (
"fmt"
"net/http"
"github.com/rs/zerolog/log"
)
func headersHandler(w http.ResponseWriter, r *http.Request) {
log.Info().Msg("Entering headersHandler")
fmt.Fprintf(w, "Request Headers\n\n")
log.Debug().Msg("Request Headers:")
for name, values := range r.Header {
log.Debug().Interface(name, values).Send()
fmt.Fprintf(w, "%s = %s\n", name, values)
}
}
This was a temporary route. Once I could confirm the headers, I deleted it.
Additionally, I had to enable Google's People API for the ProjectId where my web application was being hosted.
Afterwards, I did a test using the Go package for google.golang.org/api/people/v1 and found that the convention of using the currently authenticated user via people/me didn't work in my case since it returns the service account being used. Instead, I had to programmatically fill in the user id people/userid. Then it worked.
For my use-case, I created a /user route to return a subset of the user information, i.e. name, email, photo url.
Struct:
type GoogleUser struct {
Name string `json:"name"`
Email string `json:"email"`
PhotoUrl string `json:"photo_url"`
}
Handler:
func userHandler(w http.ResponseWriter, r *http.Request) {
log.Info().Msg("Entering userHandler")
var err error
// Make sure this is a valid API request
// Request header Content-Type: application/json must be present
if !ValidAPIRequest(r) {
err = writeJSONError(w, ResponseStatusNotFound("Not found"))
if err != nil {
log.Error().Msg(err.Error())
}
return
}
// Extract user id from header
var userId string = r.Header.Get("X-Goog-Authenticated-User-Id")
if userId != "" {
userId = strings.ReplaceAll(userId, "accounts.google.com:", "")
}
// Extract user email from header
var userEmail string = r.Header.Get("X-Goog-Authenticated-User-Email")
if userEmail != "" {
userEmail = strings.ReplaceAll(userEmail, "accounts.google.com:", "")
}
// Get the currently authenticated Google user
googleUser, err := GetCurrentGoogleUser(userId, userEmail)
if err != nil {
log.Error().Msg(err.Error())
err = writeJSONError(w, ResponseStatusInternalError(err.Error()))
if err != nil {
log.Error().Msg(err.Error())
}
return
}
// Write the JSON response
err = writeJSONGoogleUser(w, http.StatusOK, &googleUser)
if err != nil {
log.Error().Msg(err.Error())
}
}
Google People API:
func GetCurrentGoogleUser(userId string, userEmail string) (GoogleUser, error) {
// Pre-conditions
if userId == "" {
return GoogleUser{}, errors.New("userId is blank")
}
if userEmail == "" {
return GoogleUser{}, errors.New("userEmail is blank")
}
log.Debug().
Str("userId", userId).
Str("userEmail", userEmail).
Send()
ctx := context.Background()
// Instantiate a new People service
peopleService, err := people.NewService(ctx, option.WithAPIKey(GoogleAPIKey))
if err != nil {
return GoogleUser{}, err
}
// Define the resource name using the user id
var resourceName string = fmt.Sprintf("people/%s", userId)
// Get the user profile
profile, err := peopleService.People.Get(resourceName).PersonFields("names,photos").Do()
if err != nil {
return GoogleUser{}, err
}
log.Debug().
Interface("profile", profile).
Send()
return GoogleUser{Name: profile.Names[0].DisplayName, Email: userEmail, PhotoUrl: profile.Photos[0].Url}, nil
}

Get Access Token Azure AD using client certificate with Golang

I am trying to do the modern authentication from azure ad with client certificate.
The process says.
Create an azure application.
Upload the certificate to azure application and get the thumbprint.
Generate the JWT token using that certificate(https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-certificate-credentials)
Then use that jwt-token to get the access-token.
To get the access-token, call an API (https://login.microsoftonline.com//oauth2/token)
The HTTP method is of type POST and post body data will be x-www-form-urlencoded
After doing all the steps when i try to get the token.
I get this error.
{
"error": "invalid_client",
"error_description": "AADSTS700023: Client assertion audience claim does not match Realm issuer. Review the documentation at https://learn.microsoft.com/azure/active-directory/develop/active-directory-certificate-credentials .\r\nTrace ID: 714b5009-b74d-46b5-bd0e-3bea76272a01\r\nCorrelation ID: 2cb703bb-f325-44b5-a669-605bc7a81ac0\r\nTimestamp: 2020-08-28 07:31:19Z",
"error_codes": [
700023
],
"timestamp": "2020-08-28 07:31:19Z",
"trace_id": "714b5009-b74d-46b5-bd0e-3bea76272a01",
"correlation_id": "2cb703bb-f325-44b5-a669-605bc7a81ac0"
}
I am generating the JWT token using go code and parsing the PFX file.
func getAuthJWTToken() (string, error) {
clientID := "**********************"
_tenantName := "******************"
pfxFilePath := `E:\abcd.pfx`
certPassword := `*********`
authToken := ""
pfxFile, err := os.Open(pfxFilePath)
if err != nil {
return authToken, err
}
pfxfileinfo, _ := pfxFile.Stat()
var size int64 = pfxfileinfo.Size()
pfxbytes := make([]byte, size)
buffer := bufio.NewReader(pfxFile)
_, err = buffer.Read(pfxbytes)
//PFX to PEM for computation of signature
var pembytes []byte
blocks, err := pkcs12.ToPEM(pfxbytes, certPassword)
for _, b := range blocks {
pembytes = append(pembytes, pem.EncodeToMemory(b)...)
}
//Decoding the certificate contents from pfxbytes
pk, cert, err := pkcs12.Decode(pfxbytes, certPassword)
if cert == nil {
fmt.Printf("Bye")
return authToken, nil
}
if pk == nil {
}
pfxFile.Close() // close file
notToBeUsedBefore := time.Now()
expirationTime := time.Now().Add(3000 * time.Minute)
URL := fmt.Sprintf("https://login.microsoftonline.com/%s/oauth2/token", _tenantName)
id := guid.New()
claims := &claims{
StandardClaims: jwt.StandardClaims{
// In JWT, the expiry time is expressed as unix milliseconds
ExpiresAt: expirationTime.Unix(),
Audience: URL,
Issuer: clientID, // consumer key of the connected app, hardcoded
NotBefore: notToBeUsedBefore.Unix(),
Subject: clientID,
Id: id.String(),
},
}
//token_header map[string]interface{}
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
sha1Fingerprint := sha1.Sum(cert.Raw)
var slice []byte
slice = sha1Fingerprint[:]
b64FingerPrint := base64.StdEncoding.EncodeToString([]byte(slice))
token.Header["x5t"] = b64FingerPrint
signKey, err := jwt.ParseRSAPrivateKeyFromPEM(pembytes) // parse the RSA key
tokenString, err := token.SignedString(signKey) // sign the claims with private key
fmt.Printf(fmt.Sprintf("JWT token is %s", tokenString))
return tokenString, err
}
I need the help to resolve this issue.

How to pass the header in POST method?

Here I have a function in which I'm sending a POST request which is used to save customer in the squareup with data and also set the headers with Authentication using variable_name.Header.Set()
But in body response it will always give me error of the:-
"errors":[
{"category":"AUTHENTICATION_ERROR",
"code":"UNAUTHORIZED",
"detail":"Your request did not include an `Authorization` http header with an access token. }]}
But In the function I'm setting the authentication token.
Code:-
func CreateCustomer(c *gin.Context) {
customer := models.Customer{}
bearer := strings.Split(c.Request.Header["Authorization"][0], "Bearer")// token pass in the postman.
bearerToken := strings.TrimSpace(bearer[1])
customerErr := json.NewDecoder(c.Request.Body).Decode(&customer)
if customerErr != nil {
fmt.Println(customerErr)
return
}
fmt.Println(customer)
bindData, err := json.Marshal(customer)
if err != nil {
panic(err)
}
var jsonStr = []byte(string(bindData))
url :="https://connect.squareup.com/v2/customers"
fmt.Println(url)
req, err := http.Post(url, "application/json", bytes.NewBuffer(jsonStr))
// I used this one too.
// req.Header.Set("Authorization", "Bearer "+bearerToken)
// req.Header.Set("Accept", "application/json")
req.Header.Add("Authorization", "Bearer "+bearerToken)
req.Header.Add("Accept", "application/json")
fmt.Println(req.Header)
if err != nil {
panic(err)
}
defer req.Body.Close()
body, _ := ioutil.ReadAll(req.Body)
fmt.Println("response Body:", string(body))
}
type Customer struct {
GivenName string `json:"given_name" bson:"given_name"`
FamilyName string `json:"family_name" bson:"family_name"`
CompanyName string `json:"company_name" bson:"company_name"`
Nickname string `json:"nickname" bson:"nickname"`
EmailAddress string `json:"email_address" bson:"email_address"`
Address Addresss `json:"address" bson:"address"`
PhoneNumber string `json:"phone_number" bson:"phone_number"`
ReferenceId string `json:"reference_id" bson:"reference_id"`
Note string `json:"note" bson:"note"`
}
The req.Header result is:-
map[X-Xss-Protection:[1; mode=block]
Keep-Alive:[timeout=60]
Accept:[application/json]
X-Permitted-Cross-Domain-Policies:[none]
Content-Type:[application/json]
Vary:[Origin, Accept-Encoding]
X-Content-Type-Options:[nosniff]
X-Download-Options:[noopen]
X-Frame-Options:[SAMEORIGIN]
Date:[Wed, 12 Dec 2018 03:41:16 GMT]
Strict-Transport-Security:[max-age=631152000]
Authorization:[Bearer YOUR_TOKEN HERE]]
Can anyone tell me that what error should I'm doing or where I do correction that it will able to save customer in the Squareup?
Your code sends POST request and after request is processed it adds headers to response struct:
response, err := http.Post(url, "application/json", bytes.NewBuffer(jsonStr))
You should set headers first and send request after that:
// create request
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
if err != nil {
panic(err)
}
// set headers
req.Header.Add("Authorization", "Bearer "+bearerToken)
req.Header.Add("Accept", "application/json")
// send request with headers
client := &http.Client{}
response, err := client.Do(req)
#Dmitry Harnitski this is the correct approach. Only reminder is that, try not confused between "authentication" and "authorization", which was kind of roadblock I encountered. It's not about literally meaning, everyone knows the difference. However, even in the syntax, a lot material used these two words interchangeably, which should not be encouraged, at least to my mind. The topic above is a good example: began with "authentication" as the question, then ended with "authorization" as the solution.

Resources