I have a go api, and we are trying to send a message on a channel thanks to oAuth2.
So far, we retrieved the token and we can display some user information (email, username etc...)
we are trying to retrieve some message, but we have an "unauthorized" error.
I read some documentation about permissions, i think i have to do somethings with header, but i'm totally new to golang.
can you help me? :)
this is the code :
func HelloDiscord(w http.ResponseWriter, r *http.Request){
conf := &oauth2.Config{
RedirectURL: "http://localhost:8080/auth/discord",
ClientID: "clientid",
ClientSecret: "clientsecret",
Scopes: []string{discord.ScopeIdentify},
Endpoint: discord.Endpoint,
}
token, _ := conf.Exchange(context.Background(), r.FormValue("code"))
fmt.Println(token)
message, err := conf.Client(context.Background(), token).Get("https://discord.com/api/channels/1021410887191507004/messages")
fmt.Println("message;")
fmt.Println(message)
if err != nil || message.StatusCode != 200 {
w.WriteHeader(http.StatusInternalServerError)
if err != nil {
w.Write([]byte(err.Error()))
} else {
w.Write([]byte(message.Status))
}
return
}
defer message.Body.Close()
body, err := ioutil.ReadAll(message.Body)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
w.Write(body)
}
thanks a lot
Related
I did all of this: Google OAuth 2 authorization - Error: redirect_uri_mismatch
I have added auth Uri's, but still doesn't work
"redirect_uris":["https://localhost:8080","http://localhost:8080","http://localhost:8080/google_login","http://localhost:8080/google_callback","https://localhost","http://localhost"]
But Im still getting this error message:
My main.go:
func main() {
// load configs
godotenv.Load(".env")
config.SetupConfig()
// create a router
mux := http.NewServeMux()
// define routes
mux.HandleFunc("/google_login", controllers.GoogleLogin)
mux.HandleFunc("/google_callback", controllers.GoogleCallback)
// run server
log.Println("started server on :: http://localhost:8080/")
if oops := http.ListenAndServe(":8080", mux); oops != nil {
log.Fatal(oops)
}
}
contants.go:
func SetupConfig() *oauth2.Config {
conf := &oauth2.Config{
ClientID: os.Getenv("NoteClientId"),
ClientSecret: os.Getenv("NoteClientSecret"),
RedirectURL: "http://localhost:8080/google/callback",
Scopes: []string{
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/userinfo.profile",
},
Endpoint: google.Endpoint,
}
return conf
}
google.go:
func GoogleLogin(res http.ResponseWriter, req *http.Request) {
googleConfig := config.SetupConfig()
url := googleConfig.AuthCodeURL("randomstate")
http.Redirect(res, req, url, http.StatusSeeOther)
}
func GoogleCallback(res http.ResponseWriter, req *http.Request) {
state := req.URL.Query()["state"][0]
if state != "randomstate" {
fmt.Fprintln(res, "states dont match")
return
}
code := req.URL.Query()["code"][0]
googleConfig := config.SetupConfig()
token, err := googleConfig.Exchange(context.Background(), code)
if err != nil {
fmt.Fprintln(res, "Code-Token Exchange failed")
}
resp, err := http.Get("https://www.googleapis.com/oauth2/v2/userinfo?access_token=" + token.AccessToken)
if err != nil {
fmt.Fprintln(res, "User data fetch failed")
}
userData, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Fprintln(res, "Json Parsing Failed")
}
fmt.Fprintln(res, string(userData))
}
None of these URIs
["https://localhost:8080","http://localhost:8080","http://localhost:8080/google_login","http://localhost:8080/google_callback","https://localhost","http://localhost"]
march the redirect URI you have configured in constants.go
RedirectURL: "http://localhost:8080/google/callback",
Change one or the other so that they match
I am exploring OAuth2 authentication and set up a server that authenticates with Github. I followed this example, and was able to get it working. I wanted to continue on with some of the suggestions and implement a basic session token system and make the Github calls from my server as opposed to sending the Authorization token to the client.
Here is my slightly modified /oauth/redirect handler
func oauthRedirectHandler(w http.ResponseWriter, r *http.Request) {
fmt.Println("/oauth/redirect")
err := r.ParseForm()
if err != nil {
fmt.Fprintf(os.Stdout, "could not parse query: %+v", err)
w.WriteHeader(http.StatusBadRequest)
}
code := r.FormValue("code")
reqURL := fmt.Sprintf("https://github.com/login/oauth/access_token?client_id=%s&client_secret=%s&code=%s", clientID, clientSecret, code)
req, err := http.NewRequest(http.MethodPost, reqURL, nil)
if err != nil {
fmt.Fprintf(os.Stdout, "could not create HTTP request: %v", err)
w.WriteHeader(http.StatusBadRequest)
}
req.Header.Set("accept", "application/json")
res, err := httpClient.Do(req)
if err != nil {
fmt.Fprintf(os.Stdout, "could not send HTTP request: %+v", err)
w.WriteHeader(http.StatusInternalServerError)
}
defer res.Body.Close()
var t oAuthAccessResponse
if err := json.NewDecoder(res.Body).Decode(&t); err != nil {
fmt.Fprintf(os.Stdout, "could not parse JSON response: %+v", err)
w.WriteHeader(http.StatusBadRequest)
}
newSession := sessionTracker{
AccessToken: accessToken,
TimeOut: time.Now().Add(time.Minute * 15),
}
sessionToken := uuid.New().String()
sessionTrackerCache[sessionToken] = newSession
http.SetCookie(w, &http.Cookie{
Name: sessionTokenConst,
Value: sessionToken,
Expires: newSession.TimeOut,
Domain: "localhost",
})
http.Redirect(w, r, "/welcome.html", http.StatusFound)
}
It redirects to the welcome page with an attached cookie that includes my SessionToken id.
Here is my welcomeHandler
func welcomeHandler(w http.ResponseWriter, req *http.Request) {
fmt.Println("/welcome")
cookie, err := req.Cookie(sessionTokenConst)
if err != nil {
fmt.Fprintf(os.Stdout, "no cookie attached: %+v", err)
w.WriteHeader(http.StatusBadRequest)
return
}
dat, err := ioutil.ReadFile("./public/welcome.html")
if err != nil {
fmt.Fprintf(os.Stdout, "could not read welcome page: %+v", err)
w.WriteHeader(http.StatusInternalServerError)
}
fmt.Fprintf(w, string(dat))
}
Observing my browser's network tab, I authenticate with Github and my server is able to see the authorization token. The redirect response at the end of the oauthRedirectHandler contains the cookie with the SessionID. My issue lies in the fact that the browser does not seem to attach the token on the GET call to /welcome.html. I can confirm this in both the browser and in the welcomeHandler.
This is all hosted locally.
I'm not sure if this is a issue with my server, my browser, or if my understanding that cookies are applied by the browser to any future client requests until the cookie expiration date is wrong.
Any help is appreciated!
Browsers default the cookie path to the request path. Set the path to "/" to make the cookie available across the site.
Do not set the domain unless you specifically have a reason to do so (thank you Volker for noting that).
http.SetCookie(w, &http.Cookie{
Name: sessionTokenConst,
Value: sessionToken,
Path: "/", // <--- add this line
Expires: newSession.TimeOut,
// Domain: "localhost", <-- Remove this line
})
I make project Go gin
I make send an SMS message for user phone number
When the implementation of the code is completed and the program is executed, the following error occurs
InvalidClientTokenId: The security token included in the request is invalid.
I think the error course missing token.
but I don`t know get how to get token
this below my code
func PushSms(phoneNumber, code string) error {
fmt.Println("create session")
AccessKey := os.Getenv("AWS_ACCESS_KEY")
SecretAccessKey := os.Getenv("AWS_SECRET_ACCESS_KEY")
sess, err := session.NewSession(&aws.Config{
Region: aws.String("ap-northeast-1"),
Credentials: credentials.NewStaticCredentials(AccessKey, SecretAccessKey, ""),
})
if err != nil {
log.Fatalln(err)
}
svc := sns.New(sess)
input := &sns.PublishInput{
Message: aws.String("test" + code),
PhoneNumber: aws.String(phoneNumber),
}
result, err := svc.Publish(input)
if err != nil {
log.Println(err)
}
fmt.Println(result)
return nil
}
thanks
this issue change part of session.NewSession change code
sess, err := session.NewSession(&aws.Config{
Region: aws.String("ap-northeast-1"),
Credentials: credentials.NewStaticCredentials(AccessKey, SecretAccessKey, ""),
})
to
.env
AWS_ACCESS_KEY=access_key
AWS_SECRET_ACCESS_KEY=secret_access_key
AWS_REGION=ap-northeast-1
sess, err := session.NewSession()
thanks
I am trying to connect to IBM Watson's speech to text WebSocket with a new account, that has IAM authorization only.
My WS endpoint is wss://stream-fra.watsonplatform.net/text-to-speech/api/v1/recognize and I get an access token via https://iam.bluemix.net/identity/token. Now when I open the socket connection with Authorization header with value Bearer token I get a bad handshake response: websocket: bad handshake, Unauthorized 401. Language is Go.
Am I doing something wrong or it is not possible to connect to Watson's speech to text WebSocket without username/password authentication i.e. the deprecated watson-token?
EDIT:
Code to open WebSocket:
headers := http.Header{}
headers.Set("Authorization", "Bearer " + access_token)
conn, resp, err := websocket.DefaultDialer.Dial("wss://stream-fra.watsonplatform.net/text-to-speech/api/v1/recognize", headers)
I have also tried basic authorization with apikey:**api_key** and the result is the same: 401.
EDIT 2:
Code to get the access token (based on the Watson Swift and Python SDKs) which succeeds and returns access and refresh tokens:
func getWatsonToken(apiKey string) (string, error) {
// Base on the Watson Swift and Python SDKs
// https://github.com/watson-developer-cloud/restkit/blob/master/Sources/RestKit/Authentication.swift
// https://github.com/watson-developer-cloud/python-sdk/blob/master/watson_developer_cloud/iam_token_manager.py
const tokenUrl = "https://iam.bluemix.net/identity/token"
form := url.Values{}
form.Set("grant_type", "urn:ibm:params:oauth:grant-type:apikey")
form.Set("apikey", apiKey)
form.Set("response_type", "cloud_iam")
// Token from simple "http.PostForm" does not work either
//resp, err := http.PostForm(tokenUrl, form)
req, err := http.NewRequest(http.MethodPost, tokenUrl, nil)
if err != nil {
log.Printf("could not create HTTP request to get Watson token: %+v", err)
return "", nil
}
header := http.Header{}
header.Set("Content-Type", "application/x-www-form-urlencoded")
header.Set("Accept", "application/json")
// "Yng6Yng=" is "bx:bx"
header.Set("Authorization", "Basic Yng6Yng=")
req.Header = header
req.Body = ioutil.NopCloser(bytes.NewReader([]byte(form.Encode())))
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Printf("problem executing HTTP request to get Watson token: %+v", err)
return "", err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return "", errors.New(fmt.Sprintf("failed to get Watson token: %d", resp.StatusCode))
}
jsonBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Printf("problem reading Watson token from response body: %+v", err)
}
tokenResponse := &struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
TokenType string `json:"token_type"`
ExpiresIn int64 `json:"expires_in"`
Expiration int64 `json:"expiration"`
}{}
err = json.Unmarshal(jsonBody, tokenResponse)
if err != nil {
log.Printf("could not parse Watson token response: %+v", err)
return "", err
}
return tokenResponse.AccessToken, err
}
I made an error in the endpoint and used the text-to-speech instead of the speech-to-text. With the correct URL the WebSocket API works.
wss://stream-fra.watsonplatform.net/text-to-speech/api/v1/recognize should be wss://stream-fra.watsonplatform.net/speech-to-text/api/v1/recognize
We have an oauth2 endpoint that seems to require a client_credentials token to use as a Bearer for the initial code to token exchange process. I have successfully obtained the token for that.
However, in go's current implementation of oauth2 client lib, the Exchange() function (see: Exchange which eventually calls RetrieveToken)
It doesn't add an "Authentication: Bearer " header with a token I can slip in during the Exchange. It can however add a Basic auth header. Our implementation does not currently support basic auth though.
If possible, I'd like to make it add the header without modifying the source code to to oauth2 package.
It would appear if I call oauth2.RegisterBrokenAuthHeaderProvider it might skip the attempt to add a basic auth header which is needed in my case since that'll not work.
Then finally the call to do the http request which is setup as a POST.
Code:
func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, v url.Values) (*Token, error) {
hc, err := ContextClient(ctx)
if err != nil {
return nil, err
}
bustedAuth := !providerAuthHeaderWorks(tokenURL)
if bustedAuth {
if clientID != "" {
v.Set("client_id", clientID)
}
if clientSecret != "" {
v.Set("client_secret", clientSecret)
}
}
req, err := http.NewRequest("POST", tokenURL, strings.NewReader(v.Encode()))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
if !bustedAuth {
req.SetBasicAuth(url.QueryEscape(clientID), url.QueryEscape(clientSecret))
}
r, err := ctxhttp.Do(ctx, hc, req)
if err != nil {
return nil, err
}
// rest of code ...
}
the ctxhttp.Do can take a context. I've been reading about these but I don't understand how they work. Can I use them to add my header or any other headers I might require?
I'm not sure if this is the most optimal way of doing it, but it seems to work. This is the redirect callback handler that is called as a result of visiting the an auth endpoint.
// Create a custom tokenSource type
type tokenSource struct{ token *oauth2.Token }
func (t *tokenSource) Token() (*oauth2.Token, error) {
fmt.Println("TokenSource!", t.token)
return t.token, nil
}
func handleCallback(w http.ResponseWriter, r *http.Request) {
state := r.FormValue("state")
if state != oauthStateString {
fmt.Printf("invalid oauth state, expected '%s', got '%s'\n", oauthStateString, state)
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
return
}
code := r.FormValue("code")
// Create a tokenSource and fill in our application Bearer token
ts := &tokenSource{
token: &oauth2.Token{
AccessToken: appToken.AccessToken,
TokenType: appToken.TokenType,
},
}
tr := &oauth2.Transport{
Source: ts,
}
ctx := context.WithValue(context.Background(), oauth2.HTTPClient, &http.Client{
Transport: tr,
})
// myConfig defined previously and in the usual way. Look at the examples.
token, err := myConfig.Exchange(ctx, code)
if err != nil {
fmt.Printf("Code exchange failed with '%s'\n", err)
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
return
}
fmt.Printf("token: %+v", token)
// token can now be used.
}