firebase

package module
v0.0.0-...-751fd55 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 27, 2019 License: Apache-2.0 Imports: 19 Imported by: 0

README

go-firebase

AppEngine friendly Firebase for Go (Golang)

Currently just the auth pieces to verify and mint custom tokens.

UPDATE: There is now an Official Firebase Admin Go SDK which is recommended instead of this package.

Why another package?

There are a few existing firebase packages for Go but none of them seemed to work quite right and / or didn't work at all with AppEngine (standard) so this is a hacked together version that works for me which I suggest you use with caution, if at all.

This package borrows heavily from prior art, mostly Firebase Server SDK for Golang

Why custom tokens?

The firebase auth system is convenient and (currently) free to use and if you're using the firebase database it's very simple and easy.

But if you have any legacy REST API that you want to use things are not quite so obvious. Sure, you could just lookup the firebase user on each request but that is really losing what makes bearer tokens so valuable - having a JWT that authorizes the request without having to keep track of server-side sessions, so you can scale your API.

You might also want some custom claims to be available in the JWT so that you can decode it on the client and adapt the UI to match the user's roles for example.

OK, so you need custom tokens.

Now you need to jump through a few hoops and will need a server to both verify the firebase issued auth tokens passed to it (for, you know, security) before correctly producing your own signed custom tokens that firebase will accept for authentication.

This is what this library does.

What do I do on the client?

You need to do a few extra steps in order to use custom tokens on the client and also get the correct JWT to pass to the backend (non-firebase) REST API.

The steps are:

  • Sign in user with signInWithEmailAndPassword or one of the 3rd party providers
  • Get the user token via user.getToken(true) (use false if just signed in)
  • Pass the token to the auth server which issues a custom token with extra claims
  • Sign the user in with that token (auth.signInWithCustomToken)
  • Get the user token via user.getToken(false) (yes, it's another token)

The last token is the one that you can send to your REST API to authorize requests. If you only need to add extra claims for use with firebase rules, the last step can be skipped.

Example tokens

Here's an example of the auth tokens showing the different versions at each step (tip: the JWT Debugger helps when working with tokens):

Token received from firebase after signInWithEmailAndPassword:

{
  "iss": "https://securetoken.google.com/captain-codeman",
  "aud": "project-name",
  "auth_time": 1479745491,
  "user_id": "RE8hG0RX4YVMHHjferfb8tu4jRr2",
  "sub": "RE8hG0RX4YVMHHjferfb8tu4jRr2",
  "iat": 1479745491,
  "exp": 1479749091,
  "email": "email@address",
  "email_verified": false,
  "firebase": {
    "identities": {
      "email": [
        "email@address"
      ]
    },
    "sign_in_provider": "password"
  }
}

Token we get back from our custom token service:

{
  "aud": "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
  "claims": {
    "roles": [
      "admin",
      "operator"
    ],
    "uid": 1
  },
  "exp": 1479749434,
  "iat": 1479745834,
  "iss": "firebase-adminsdk-0rpgf@project-name.iam.gserviceaccount.com",
  "sub": "firebase-adminsdk-0rpgf@project-name.iam.gserviceaccount.com",
  "uid": "RE8hG0RX4YVMHHjferfb8tu4jRr2"
}

Token we get after signing in with the custom token and using user.getToken():

{
  "iss": "https://securetoken.google.com/project-name",
  "roles": [
    "admin",
    "operator"
  ],
  "uid": 1,
  "aud": "project-name",
  "auth_time": 1479745834,
  "user_id": "RE8hG0RX4YVMHHjferfb8tu4jRr2",
  "sub": "RE8hG0RX4YVMHHjferfb8tu4jRr2",
  "iat": 1479745834,
  "exp": 1479749434,
  "email": "email@address",
  "email_verified": false,
  "firebase": {
    "identities": {
      "email": [
        "email@address"
      ]
    },
    "sign_in_provider": "custom"
  }
}

Note this now includes the firebase user id (as sub and user_id), our apps internal user id (as uid) and the roles we set - everything we might need to authorize a REST API call on our server (just extract and verify the JWT claims).

Server example

A very simple example server is included, note that the app/firebase-credentials.json file is not included and you should instead include one created from your own project.

Client example

I'm using Polymer for my front-end and have created an <auth-ajax> element to make auth-token handling easier.

See the demo which uses an instance of this package for the server-side custom token issuing.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AuthorizationFromHeader

func AuthorizationFromHeader(req *http.Request) (string, error)

func AuthorizationFromParam

func AuthorizationFromParam(req *http.Request) (string, error)

func AuthorizationFromRequest

func AuthorizationFromRequest(req *http.Request) (string, error)

func ContextClient

func ContextClient(ctx context.Context) (*http.Client, error)

func ContextTransport

func ContextTransport(ctx context.Context) http.RoundTripper

func RegisterContextClientFunc

func RegisterContextClientFunc(fn ContextClientFunc)

func RegisterRequestContextFunc

func RegisterRequestContextFunc(fn RequestContextFunc)

func RequestContext

func RequestContext(req *http.Request) (context.Context, error)

func ServerAllowedOrigins

func ServerAllowedOrigins(origins []string) func(*Server)

ServerAllowedOrigins sets AllowedOrigins for CORS

func ServerGenerateURI

func ServerGenerateURI(uri string) func(*Server)

ServerGenerateURI Sets URI for the token generation

func ServerVerifyURI

func ServerVerifyURI(uri string) func(*Server)

ServerVerifyURI Sets URI for token verification

func WithCredentials

func WithCredentials(creds *Credentials) func(*Config) error

WithCredentials sets the credentials

func WithCredentialsPath

func WithCredentialsPath(path string) func(*Config) error

WithCredentialsPath sets the path to load credentials from

func WithName

func WithName(name string) func(*Config) error

WithName sets the name of the app

Types

type App

type App struct {
	// contains filtered or unexported fields
}

func GetApp

func GetApp(name string) (*App, error)

func New

func New(options ...Option) (*App, error)

func (*App) Auth

func (a *App) Auth() *Auth

func (*App) Name

func (a *App) Name() string

type Auth

type Auth struct {
	// contains filtered or unexported fields
}

func (*Auth) AllRoles

func (a *Auth) AllRoles(h http.Handler, roles ...string) http.Handler

func (*Auth) AnyRole

func (a *Auth) AnyRole(h http.Handler, roles ...string) http.Handler

func (*Auth) Authenticated

func (a *Auth) Authenticated(h http.Handler, roles ...string) http.Handler

func (*Auth) Authorize

func (a *Auth) Authorize(h http.Handler, authFn AuthFunc) http.Handler

func (*Auth) CreateCustomToken

func (a *Auth) CreateCustomToken(uid string, developerClaims *Claims) (string, error)

func (*Auth) Server

func (a *Auth) Server(claimsFn CreateClaimsFunc, options ...func(*Server)) http.Handler

func (*Auth) VerifyIDToken

func (a *Auth) VerifyIDToken(ctx context.Context, token string) (*Token, error)

type AuthFunc

type AuthFunc func(*Token) (bool, error)

type Claims

type Claims map[string]interface{}

Claims to be stored in a custom token (and made available to security rules in Database, Storage, etc.). These must be serializable to JSON (e.g. contains only Maps, Arrays, Strings, Booleans, Numbers, etc.).

type Config

type Config struct {
	Name            string
	Credentials     *Credentials
	CredentialsPath string
}

Config stores firebase app configuration settings

type ContextClientFunc

type ContextClientFunc func(context.Context) (*http.Client, error)

ContextClientFunc is a func which tries to return an *http.Client given a Context value. If it returns an error, the search stops with that error. If it returns (nil, nil), the search continues down the list of registered funcs.

type ContextKey

type ContextKey struct{}

ContextKey is just an empty struct. It exists so HTTPClient can be an immutable public variable with a unique type. It's immutable because nobody else can create a ContextKey, being unexported.

var HTTPClient ContextKey

HTTPClient is the context key to use with golang.org/x/net/context's WithValue function to associate an *http.Client value with a context.

type CreateClaimsFunc

type CreateClaimsFunc func(context.Context, *Token) (*Claims, error)

type Credentials

type Credentials struct {
	// ProjectID is the project ID.
	ProjectID string
	// PrivateKey is the RSA256 private key.
	PrivateKey *rsa.PrivateKey
	// ClientEmail is the client email.
	ClientEmail string
}

func (*Credentials) UnmarshalJSON

func (c *Credentials) UnmarshalJSON(data []byte) error

UnmarshalJSON is the custom unmarshaler for GoogleServiceAccountCredential. Private key is parsed from PEM format.

type ErrorTransport

type ErrorTransport struct{ Err error }

ErrorTransport returns the specified error on RoundTrip. This RoundTripper should be used in rare error cases where error handling can be postponed to response handling time.

func (ErrorTransport) RoundTrip

func (t ErrorTransport) RoundTrip(*http.Request) (*http.Response, error)

type Option

type Option func(*Config) error

Option is the signature for configuration options

type RequestContextFunc

type RequestContextFunc func(*http.Request) (context.Context, error)

RequestContextFunc is a func which tries to return a context.Context given a Request value. If it returns an error, the search stops with that error. If it returns (nil, nil), the search continues down the list of registered funcs.

type Server

type Server struct {
	// contains filtered or unexported fields
}

type Token

type Token struct {
	jwt.JWT
}

func (*Token) Email

func (t *Token) Email() (string, bool)

Email returns the email address for this user, or nil if it's unavailable.

func (*Token) IsEmailVerified

func (t *Token) IsEmailVerified() (bool, bool)

IsEmailVerified indicates if the email address returned by Email() has been verified as good.

func (*Token) Issuer

func (t *Token) Issuer() (string, bool)

Issuer returns the issuer for this token.

func (*Token) Name

func (t *Token) Name() (string, bool)

Name returns the user's display name.

func (*Token) Picture

func (t *Token) Picture() (string, bool)

Picture returns the URI string of the user's profile photo.

func (*Token) UID

func (t *Token) UID() (string, bool)

UID returns the uid for this token.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL