Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Firebase 3 Authentication #9

Open
theprojectabot opened this issue Jun 27, 2016 · 16 comments
Open

Support Firebase 3 Authentication #9

theprojectabot opened this issue Jun 27, 2016 · 16 comments

Comments

@theprojectabot
Copy link

When attempting an auth from a generated token by fire auth I am getting:
FIRAuthErrorDomain Code=17000 "The custom token format is incorrect. Please check the documentation."

@zabawaba99
Copy link
Owner

It looks like it's not supported. I will not be able to get to this for a couple of hours but it will be top of my todo list.

In the meantime, if you know what the issue is and/or would like to open a PR I can review it and merge it quicker.

@theprojectabot
Copy link
Author

looks like the library needs to be changed to support a private key from a Firebase spawned service JSON file

https://firebase.google.com/docs/auth/server#use_a_jwt_library

Then the fireauth library could use that private key, mint a JWT token and then I can send to my client (iOS in this case)

@theprojectabot
Copy link
Author

I tried this:

...
now := time.Now().Unix()
    jwtToken := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{

        "iss": serviceAccountEmail,
        "sub": serviceAccountEmail,
        "aud": "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
        "iat": now,
        "exp": now + (60 * 60), // Maximum expiration time is one hour
        "uid": u.UID,
        /*
           "claims" : array(
               "premium_account" : true
           )*/

    })

    // Sign and get the complete encoded token as a string using the secret
    token, err = jwtToken.SignedString(privateKey)

    fmt.Println(token, err)

...

Im using the jwt-go library

but I get 'key invalid' when I send in my privateKey that I received when I got a service account key from google developer portal.

@theprojectabot
Copy link
Author

@zabawaba99
Copy link
Owner

I'm in the firebase-community slack if you want to have a bit more of a back and forth on it. I'm looking at the examples you posted now.

@zabawaba99
Copy link
Owner

I used the snippet that you gave and got a different error

2016/06/27 14:33:11 test did not pass {
  "error" : "Missing claim 'kid' in auth header."
}
exit status 1

What I did have to do was format and replaced the \n with actual spaces. Something like

secret := []byte(`-----BEGIN PRIVATE KEY-----
helloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworld
helloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworld
helloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworld
-----END PRIVATE KEY-----
`)

@theprojectabot
Copy link
Author

theprojectabot commented Jun 27, 2016

I got it to work!

signKey, err := jwt.ParseRSAPrivateKeyFromPEM(privateKey)
    if err != nil {
        log.Print(err)
    }

    token, err = jwtToken.SignedString(signKey)

had to make sure that the key I got from google services was then parsed into the interface that jwt-go wanted then I got back a signed string that works with my iOS auth call.

@zabawaba99 zabawaba99 changed the title tokens are not valid Support Firebase 3 Authentication Jun 28, 2016
@zabawaba99
Copy link
Owner

Also found a similar issue on a ruby client as well CodementorIO/rest-firebase#12

@theprojectabot
Copy link
Author

theprojectabot commented Jun 28, 2016

@zabawaba99 I didnt need to include the 'kid' in my code. Though I did comment out the claims array in the payload I handed to jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{

@zabawaba99
Copy link
Owner

@theprojectabot Was the kid part of the auth header or the MapClaims?

@tqwewe
Copy link

tqwewe commented Dec 29, 2016

I'm having trouble replicating what @theprojectabot did.
Here is my current code:

jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
	"uid": "1",
})

signKey, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(`I don't know what to put here, I tried a number of things including randomly generated private RSA keys`))
if err != nil {
	log.Fatal(err)
}

token, err := jwtToken.SignedString(signKey)
if err != nil {
	log.Fatal(err)
}

tmpl, err := template.ParseFiles("index.html")
if err != nil {
	log.Fatal(err)
}

if err := tmpl.Execute(w, token); err != nil {
	log.Fatal(err)
}

I recive the error message

Invalid Key: Key must be PEM encoded PKCS1 or PKCS8 private key

when trying to run this code.

I am trying to authenticate Steam OAuth with Firebase but the internet has absolutely nothing for it.

@zabawaba99
Copy link
Owner

@acidic9 following the instructions here on how to generate a private key for your application. You will be prompted to download a JSON file as your final step. This JSON file contains the private key you would put jwt.ParseRSAPrivateKeyFromPEM([]byte('here'))

@tqwewe
Copy link

tqwewe commented Dec 29, 2016

I downloaded the JSON file, extracted the PrivateKey but when trying to use it with jwt.ParseRSAPrivateKeyFromPEM([]byte(privateKey)) It outputs 'key is invalid'.

I tried using strings.Replace(fbInfo.PrivateKey, `\n`, ` `, -1) as the private key (replacing \n with spaces) but it still output's the same error.

Here is the code I am trying to run:

package main

import (
	"encoding/json"
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"io/ioutil"
	"log"
	"strings"
)

type firebaseInfo struct {
	AuthProviderX509CertURL string `json:"auth_provider_x509_cert_url"`
	AuthURI                 string `json:"auth_uri"`
	ClientEmail             string `json:"client_email"`
	ClientID                string `json:"client_id"`
	ClientX509CertURL       string `json:"client_x509_cert_url"`
	PrivateKey              string `json:"private_key"`
	PrivateKeyID            string `json:"private_key_id"`
	ProjectID               string `json:"project_id"`
	TokenURI                string `json:"token_uri"`
	Type                    string `json:"type"`
}

func main() {
	// Read Firebase json file.
	fbInfoContent, err := ioutil.ReadFile("firebase-json.json")
	if err != nil {
		log.Fatal(err)
	}

	// Unmarshal json into fbInfo.
	var fbInfo firebaseInfo
	if err = json.Unmarshal(fbInfoContent, &fbInfo); err != nil {
		log.Fatal(err)
	}

	// Format privateKey.
	privateKey := strings.Replace(fbInfo.PrivateKey, `\n`, ` `, -1)

	// Create jwtToken with SigningMethodHS256.
	jwtToken := jwt.New(jwt.SigningMethodHS256)

	// Create signKey by parsing RSA private key.
	signKey, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(privateKey))
	if err != nil {
		log.Fatal(err)
	}

	// Generate token with signKey.
	token, err := jwtToken.SignedString(signKey)
	if err != nil {
		log.Fatal(err)
	}

	// Finally, after 100000 google searches my problem may be solved.
	// Thank you heaps for helping me! :)
	fmt.Println("SUCCESS:", token)
}

Output: key is invalid

@zabawaba99
Copy link
Owner

@acidic9 try this

package main

import (
	"encoding/json"
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"io/ioutil"
	"log"
	"time"
)

type firebaseInfo struct {
	AuthProviderX509CertURL string `json:"auth_provider_x509_cert_url"`
	AuthURI                 string `json:"auth_uri"`
	ClientEmail             string `json:"client_email"`
	ClientID                string `json:"client_id"`
	ClientX509CertURL       string `json:"client_x509_cert_url"`
	PrivateKey              string `json:"private_key"`
	PrivateKeyID            string `json:"private_key_id"`
	ProjectID               string `json:"project_id"`
	TokenURI                string `json:"token_uri"`
	Type                    string `json:"type"`
}

func main() {
	// Read Firebase json file.
	fbInfoContent, err := ioutil.ReadFile("firebase-json.json")
	if err != nil {
		log.Fatal(err)
	}

	// Unmarshal json into fbInfo.
	var fbInfo firebaseInfo
	if err = json.Unmarshal(fbInfoContent, &fbInfo); err != nil {
		log.Fatal(err)
	}

	// Create jwtToken with SigningMethodHS256.
	now := time.Now().Unix()
	jwtToken := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
		"iss": fbInfo.ClientEmail,
		"sub": fbInfo.ClientEmail,
		"aud": "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
		"iat": now,
		"exp": now + (60 * 60), // Maximum expiration time is one hour
		"uid": "Some identifier for the user",
	})

	// Create signKey by parsing RSA private key.
	signKey, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(fbInfo.PrivateKey))
	if err != nil {
		log.Fatal("error parsing rsa", err)
	}

	// Generate token with signKey.
	token, err := jwtToken.SignedString(signKey)
	if err != nil {
		log.Fatal("error signing string", err)
	}

	// Finally, after 100000 google searches my problem may be solved.
	// Thank you heaps for helping me! :)
	fmt.Println("SUCCESS:", token)
}

I was able to get the snippet above working. A few notes:

  • A private key needs the new lines. By removing them, the key is invalid.
  • There are specific claims you need to pass into your token in order to create a valid one. Without it Firebase will accept your token.

@tqwewe
Copy link

tqwewe commented Dec 30, 2016

Thank you so so much man, seriously, I was trying to find a solution for so long and finally it works. I really appreciate you fixing it up for me!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants