Users are authenticated in the frontend via
const googleAuthProvider = new firebase.auth.GoogleAuthProvider();
firebase.auth().signInWithPopup(googleAuthProvider);
after that I am calling a cloud function with the firebase callable:
const nodeStateCall = functions.httpsCallable('myFunction');
nodeStateCall().then(...);
This workks without any problems and I recieve the jwt token in my go function.
I tried many different variations to authenticate this token. The function which I am using now is idtoken.Validate() from the google.golang.org/api/idtoken pacakge.
My function:
func verifyIdToken(idToken string)(tokenInfo *idtoken.Payload, err error) {
log.Print("running verify Token")
splitToken := strings.Split(idToken, "Bearer ")[1]
log.Print("split Token:"+splitToken)
tokenInfo, err = idtoken.Validate(context.Background(),splitToken,"MYAUDIENCE")
if err != nil {
log.Print("error from tokenInfoCall.Do()")
log.Print(err)
return nil, err
}
log.Print("Finished verify token.")
return tokenInfo, nil
}
but I keep getting "invalid value" when I send the token.
I also tried the oauth2 service:
oauth2Service, err := oauth2.NewService(context.Background())
tokenInfoCall := oauth2Service.Tokeninfo()
tokenInfoCall.IdToken(splitToken)
tokenInfo, err := tokenInfoCall.Do()
which didn't work either.
What do I have to do to validate the firebase jwt token in my go function?
Because you are using firebase service, you need to use this to verify your token:
https://firebase.google.com/docs/auth/admin/verify-id-tokens#verify_id_tokens_using_the_firebase_admin_sdk
Note that you should setup your function in the same project so the library will query correctly.
Related
I've registered on Spotify my app and I obtained my credentials.
I'm using Spotify web api through zmb3/spotify Go wrapper.
const redirectURI = "http://localhost:8080/auth_callback" //Already registered
const CLIENT_ID = "myId"
const CLIENT_SECRET = "mySecret"
const STATE = "myState"
I have a local server (written in Golang) listening for requests on some routes. When I define routes, I create the Spotify Authenticator with desired scopes and I obtain the url.
If I print the authorize url to stdout and I click it (or also with copy and paste) redirectURI is correctly called!
Here is the code...
var auth spotify.Authenticator
var token *oauth2.Token
var client spotify.Client
var authorize_url string
func main(){
fmt.Println("[MAIN] Starting Server")
auth = spotify.NewAuthenticator(redirectURI, spotify.ScopeUserReadPrivate, spotify.ScopeUserTopRead)
auth.SetAuthInfo(CLIENT_ID, CLIENT_SECRET)
authorize_url = auth.AuthURL(STATE)
var wg sync.WaitGroup
router.HandleFunc("/authorize_spotify", authHandler)
router.HandleFunc("/auth_callback", completeAuth)
http.Handle("/", router)
wg.Add(1)
go start(&wg, 0)
defer wg.Wait()
fmt.Println("[MAIN] Running Server... " + url)
}
//SPOTIFY API MANAGEMENT
func completeAuth(w http.ResponseWriter, r *http.Request) {
fmt.Println("Authentication Redirect Received")
token, err := auth.Token(STATE, r)
if err != nil {
http.Error(w, "Couldn't get token", http.StatusForbidden)
log.Fatal(err)
}
if st := r.FormValue("state"); st != STATE {
http.NotFound(w, r)
log.Fatalf("State mismatch: %s != %s\n", st, STATE)
}
// use the token to get an authenticated client
println(token)
client = auth.NewClient(token)
}
Now I want to make /authorize_spotify automatically call the obtained url.
I wrote these two lines.
func authHandler(w http.ResponseWriter, r *http.Request){
fmt.Println("[AUTH - HANDLER]")
http.Redirect(w, r, authorize_url, 302)
}
However, when I contact localhost:8080/authorize_spotify
authHandler is NEVER Called (no output on stdout, despite the fmt.Println(...)).
Misteriously, I'm redirected to the redirectURI at the same way, but it fails.
Seeing network http exchanges I noted that the authorize_url that I printed is a bit different from the authorize request misteriously sent (in the latter the user-top-read scope is missing), that confirms that the authHandler is not called.
How can I achieve my token calling authorize_url from code?
Thanks in advance!
Is there any way to verify if Firebase Admin SDK Credentials is correct when initializing app with below code?
ctx := context.Background()
opt := option.WithCredentialsFile("path/to/firebase-admin-sdk-cred.json")
app, err := firebase.NewApp(ctx, nil, opt)
if err != nil {
return nil, err
}
Because I seem to not get any error when I tried to intentionally put the wrong credentials. I check the implementation of the firebase.NewApp() but it seems it only throw error when there is no config. Below is the code of firebase.NewApp()
func NewApp(ctx context.Context, config *Config, opts ...option.ClientOption) (*App, error) {
o := []option.ClientOption{option.WithScopes(internal.FirebaseScopes...)}
o = append(o, opts...)
if config == nil {
var err error
if config, err = getConfigDefaults(); err != nil {
return nil, err
}
}
pid := getProjectID(ctx, config, o...)
ao := defaultAuthOverrides
if config.AuthOverride != nil {
ao = *config.AuthOverride
}
return &App{
authOverride: ao,
dbURL: config.DatabaseURL,
projectID: pid,
serviceAccountID: config.ServiceAccountID,
storageBucket: config.StorageBucket,
opts: o,
}, nil
}
so Is there any way to check if the credentials is valid during the initialization of Firebase Admin(app) instance because it seems catching error isn't the solution here?
I think the answer is in the documentation:
Some use cases require you to create multiple apps at the same time.
For example, you might want to read data from the Realtime Database of
one Firebase project and mint custom tokens for another project. Or
you might want to authenticate two apps with separate credentials. The
Firebase SDK allows you create multiple apps at the same time, each
with their own configuration information.
Source
I assume the only way to check credentials is invoke an Auth method for example:
client, err := app.Auth(context.Background())
I ended up using google.golang.org/api/transport to force the validation and fail fast
// Check if credential is correct
_, err = transport.Creds(ctx, opt)
if err != nil {
return nil, err
}
I'm on golang app engine standard. I keep getting a 403 error when I'm using a firebase. Here is the code I'm using for passing credentials for firebase. What is this api key? What am I doing wrong?
Error:
googleapi: Error 403: The request is missing a valid API key., forbidden
credJSON := []byte("{...json from firebase console...}")
creds, err := google.CredentialsFromJSON(ctx, credJSON, "https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/datastore",
"https://www.googleapis.com/auth/devstorage.full_control",
"https://www.googleapis.com/auth/firebase",
"https://www.googleapis.com/auth/identitytoolkit",
"https://www.googleapis.com/auth/userinfo.email")
if err != nil {
return err
}
ops = append(ops, option.WithCredentials(creds))
fbApp, err := fb.NewApp(ctx, &fb.Config{ProjectID: projectID}, ops...)
Turns out if you pass nil for config. The library figures out credentials on Google Cloud. So, here is the code:
fbApp, err := fb.NewApp(ctx, nil, ops...)
if err != nil {
return nil, err
}
I'm making an app that needs to send printing jobs through Google Cloud Printing to two printers owned by me (i.e., the printers are always the same one and does not belong to the user). I've set up the printers with Google Cloud Printing and it is now accessible from my Google Account.
Now, how can I access this account's printers through the API? I have found some documentation here that says that I need to authenticate myself when making requests. It seems to me that the authentication should be done with OAuth2. But the instructions on how to do that are lacking for a beginner. I've gotten so far as to getting my OAuth client ID and secret (step 1 in the OAuth link). But for step 2, I have no idea what to do.
It says:
Before your application can access private data using a Google
API, it must obtain an access token that grants access to that API. A
single access token can grant varying degrees of access to multiple
APIs.
But doesn't explain how to obtain this access token. I looked at this SO question where OP seems to have been able to get this access token, but I can't understand how he did it.
Could someone please explain how to get an access token to use with Google Cloud Printing? Or a good resource which explains how?
PS. The printing functionality is triggered by a firebase function. Would this help us get the access token, considering firebase is also made by Google?
I ran into the same issue and came up with this two-step solution:
Create an OAuth2 client in your Google Cloud Console as described here
and download its client credentials from the console and copy & past its json content to credJSON in the code snippet below.
Run the code below.
Follow the auth link and authorize your OAuth2 client to access Googel Cloud Printers with your Google account.
Copy & paste the auth code to the script
Once you obtained a refresh token make sure to store it in the variable refreshToken
Don't forget to update the proxy name.
package main
import (
"context"
"fmt"
"log"
"github.com/google/cloud-print-connector/gcp"
"github.com/google/cloud-print-connector/lib"
"github.com/google/uuid"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
)
var (
credJSON = ``
refreshToken = ""
// Find the proxy in the Advanced Details of your printer at https://www.google.com/cloudprint#printers
proxy = "HP"
)
func main() {
// Obtain the OAuth config
config, err := google.ConfigFromJSON([]byte(credJSON), gcp.ScopeCloudPrint)
if err != nil {
log.Fatalf("Failed to obtain OAuth config: %v", err)
}
// If no request token is present, obtain a new one
if refreshToken == "" {
// Get the auth link
authLink := config.AuthCodeURL(uuid.New().String(), oauth2.AccessTypeOffline)
log.Printf("Follow the link to obtain an auth code: %s", authLink)
fmt.Printf("Paste your auth code here: ")
var code string
fmt.Scanln(&code)
// Get a token form the auth code
token, err := config.Exchange(context.Background(), code, oauth2.AccessTypeOffline)
if err != nil {
log.Fatalf("Failed to obtain OAuth token: %v", err)
}
if token.RefreshToken != "" {
refreshToken = token.RefreshToken
} else {
refreshToken = token.AccessToken
}
log.Printf("Refresh token: %s", refreshToken)
}
// Connect to Google Cloud Print
jobCh := make(chan *lib.Job)
client, err := gcp.NewGoogleCloudPrint(lib.DefaultConfig.GCPBaseURL, refreshToken, refreshToken, proxy, config.ClientID, config.ClientSecret, config.Endpoint.AuthURL, config.Endpoint.TokenURL, lib.DefaultConfig.NativeJobQueueSize, jobCh, true)
if err != nil {
log.Fatalf("Failed to connect to GCP: %v", err)
}
// List all printers
printers, _, err := client.ListPrinters()
if err != nil {
log.Fatalf("Failed to list printers: %v", err)
}
for _, p := range printers {
log.Printf("Name: %s UUID: %s", p.Name, p.UUID)
}
}
Please refer to following documentation:
https://developers.google.com/identity/protocols/OAuth2ServiceAccount?authuser=1
I followed the same steps specified in the doc and was able to obtain the access token. First make Google Service Account, select furnish new private key. You ll have service account email addresss and private key. Using these credentials, you can obtain your access token. Below is the source code in Golang , this ll surely help you.
package main
import (
"fmt"
"github.com/dgrijalva/jwt-go"
"net/http"
"encoding/json"
"bytes"
)
type MyCustomClaims struct {
Scope string `json:"scope,omitempty"`
jwt.StandardClaims
}
type Toke struct {
Access string `json:"access_token,omitempty"`
Type string `json:"token_type,omitempty"`
Expire string `json:"expires_in,omitempty"`
}
func main() {
key := []byte("<your private key>")
key1, _ := jwt.ParseRSAPrivateKeyFromPEM(key)
claims := MyCustomClaims{
"https://www.googleapis.com/auth/cloudprint",
jwt.StandardClaims{
IssuedAt: <currrent-epoch-time>, // eg 1234566000
ExpiresAt: <currrent-epoch-time + 3600>, // 3600 secs = 1hour, so expires in 1 hour, eg 1234569600
Issuer: "<your service account email>",
Audience: "https://www.googleapis.com/oauth2/v4/token",
},
}
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
ss, err := token.SignedString(key1)
if err != nil {
fmt.Println(err)
}
fmt.Println(ss)
url := "https://www.googleapis.com/oauth2/v4/token"
any := "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=" + ss
a := []byte(any)
b := bytes.NewBuffer(a)
var tok Toke
req, err := http.NewRequest("POST", url, b)
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
} else {
json.NewDecoder(resp.Body).Decode(&tok)
}
fmt.Println("----------- Access Token -----------------")
fmt.Println("Access: ", tok.Access)
}
In order to send Firebase Cloud Messaging with Go, we need to place the access token in the HTTP request header.
On Firebase documentation,
there are examples on how to retrieve the access token using Node.JS, Python and Java:
https://firebase.google.com/docs/cloud-messaging/auth-server
can anyone show the get the access token using Go?
There seems to be many Go packages about Firebase/Google authentication. It's very confusing to understand which ones should be used:
firebase.google.com/go
firebase.google.com/go/auth
github.com/firebase/firebase-admin-go
google.golang.org/api/option
golang.org/x/oauth2
golang.org/x/oauth2/google
github.com/google/google-api-go-client
I'm working on the go firebase SDK to add FCM HTTP v1.
For now it's almost finished, i have to write tests and integration tests, you can check the code here : https://github.com/chemidy/firebase-admin-go/tree/fcm/messaging
I will finish tests and send a PR maybe next week, (it's a little bit tricky to test on ios + android + web)
FCM httpv1 use JSON file for it credentials.
Download it first, then move it to your project.
download JSON credentials in your firebase
second, do :
go get "golang.org/x/oauth2/google"
then use this method to get token
const firebaseScope = "https://www.googleapis.com/auth/firebase.messaging"
type tokenProvider struct {
tokenSource oauth2.TokenSource
}
// newTokenProvider function to get token for fcm-send
func newTokenProvider(credentialsLocation string) (*tokenProvider, error) {
jsonKey, err := ioutil.ReadFile(credentialsLocation)
if err != nil {
return nil, errors.New("fcm: failed to read credentials file at: " + credentialsLocation)
}
cfg, err := google.JWTConfigFromJSON(jsonKey, firebaseScope)
if err != nil {
return nil, errors.New("fcm: failed to get JWT config for the firebase.messaging scope")
}
ts := cfg.TokenSource(context.Background())
return &tokenProvider{
tokenSource: ts,
}, nil
}
func (src *tokenProvider) token() (string, error) {
token, err := src.tokenSource.Token()
if err != nil {
return "", errors.New("fcm: failed to generate Bearer token")
}
return token.AccessToken, nil
}
Then call it in your FCM-Send method :
tp, err := newTokenProvider("yourJSONFileLocation")
if err != nil {
return nil, err
}
token, err := tp.token()
if err != nil {
return nil, err
}
last, add it to header :
r.Header.Add("Authorization", "Bearer "+token)
Done.
i am put header Authorization by used volly
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> headerMap = new HashMap<String, String>();
headerMap.put("Content-Type", "application/json");
headerMap.put("Authorization", "Bearer " + key);
Log.v(TAG,"getHeaders "+headerMap);
return headerMap;
}
but send Authorization=Bearer Add..
how change to current
Authorization:Bearer