0
votes

I notice that the docs specify that I can create a token to expire up to 3600 seconds later[1] But I don't see how to do that with auth().createCustomToken ... I can manually do it with jsonwektoken, but it seems like this should be addressable directly with firebase-admin library.

Another question is, what is the secret I need to verify my own token generated in this way, the uid ?

index.js

// demo server generating custom auth for firebase
import Koa from 'koa'
import Koajwt from 'koa-jwt'

import Token from './token'

const app = new Koa()

// Custom 401 handling if you don't want to expose koa-jwt errors to users
app.use(function(ctx, next){
  return next().catch((err) => {
    if (401 == err.status) {
      ctx.status = 401
      ctx.body = 'Protected resource, use Authorization header to get access\n'
    } else {
      throw err
    }
  })
})

// Unprotected middleware
app.use(function(ctx, next){
    if (ctx.url.match(/^\/login/)) {
        // use router , post, https to securely send an id
        const conf = {
            uid: 'sample-user-uid',
            claims: {
              // Optional custom claims to include in the Security Rules auth / request.auth variables
              appid: 'sample-app-uid'
            }
        }
        ctx.body = {
            token: Token.generateJWT(conf)
        }
    } else {
      return next();
    }
  });

// Middleware below this line is only reached if JWT token is valid
app.use(Koajwt({ secret: 'shared-secret' }))

// Protected middleware
app.use(function(ctx){
  if (ctx.url.match(/^\/api/)) {
    ctx.body = 'protected\n'
  }
})

app.listen(3000);

token.js

//import jwt from 'jsonwebtoken'
import FirebaseAdmin from 'firebase-admin'
import serviceAccount from 'demo-admin-firebase-adminsdk-$$$$-$$$$$$.json'

export default {
    isInitialized: false,

    init() {
        FirebaseAdmin.credential.cert(serviceAccount)
        isInitialized = true
    },

    /* generateJWTprimiative (payload, signature, conf) {
        // like: jwt.sign({ data: 'foobar' }, 'secret',  { expiresIn: '15m' }) 
        jwt.sign(payload, signature, conf)
    } */

    generateJWT (conf) {
        if(! this.isInitialized)
            init()

        FirebaseAdmin.auth().createCustomToken(conf.uid, conf.claims)
        .then(token => {
            return token
        })
        .catch(err => {
            console.log('no token generate because', err)
        })
    }    
}

[1] https://firebase.google.com/docs/auth/admin/create-custom-tokens

1

1 Answers

2
votes

You can't change the token expiration. The docs you found includes the words:

Firebase tokens comply with the OpenID Connect JWT spec, which means the following claims are reserved and cannot be specified within the additional claims: ... exp ...

This is further backed up by inspecting the Firebase Admin SDK source code on GitHub.

In this section:

public createCustomToken(uid: string, developerClaims?: {[key: string]: any}): Promise<string> {

 // ....  cut for length  ....

  const header: JWTHeader = {
    alg: ALGORITHM_RS256,
    typ: 'JWT',
  };
  const iat = Math.floor(Date.now() / 1000);
  const body: JWTBody = {
    aud: FIREBASE_AUDIENCE,
    iat,
    exp: iat + ONE_HOUR_IN_SECONDS,
    iss: account,
    sub: account,
    uid,
  };
  if (Object.keys(claims).length > 0) {
    body.claims = claims;
  }

  // ....  cut for length  ....

You can see the exp property is hard coded to be iat + ONE_HOUR_IN_SECONDS where the constant is defined elsewhere in the code as 60 * 60...

If you want to customize the expiration time, you will HAVE to create your own token via a 3rd party JWT package.

To your 2nd question, a secret is typically stored in the server environment variables, and is a pre-set string or password. Technically you could use the UID as the secret, but that would be a TERRIBLE idea security wise - please don't do this. Your secret should be like your password, keep it secure and don't upload it with your source code to GitHub. You can read more about setting and retrieving environment variables in Firebase in these docs here