code: func (i *Inspector) InspectToken(c context.Context, tok string) (*Inspection, error) {
  	res := &Inspection{}
  
  	enc := i.Encoding
  	if enc == nil {
  		enc = base64.RawURLEncoding
  	}
  
  	// Byte blob with serialized envelope.
  	blob, err := enc.DecodeString(tok)
  	if err != nil {
  		res.InvalidityReason = fmt.Sprintf("not base64 - %s", err)
  		return res, nil
  	}
  
  	// Deserialize the envelope into a proto message.
  	env := i.Envelope()
  	if err = proto.Unmarshal(blob, env); err != nil {
  		res.InvalidityReason = fmt.Sprintf("can't unmarshal the envelope - %s", err)
  		return res, nil
  	}
  	res.Envelope = env
  
  	// Convert opaque proto message into a struct we can work with.
  	unwrapped := i.Unwrap(res.Envelope)
  
  	// Try to deserialize the body, if possible.
  	body := i.Body()
  	if err = proto.Unmarshal(unwrapped.Body, body); err != nil {
  		res.InvalidityReason = fmt.Sprintf("can't unmarshal the token body - %s", err)
  		return res, nil
  	}
  	res.Body = body
  
  	var reasons []string
  
  	if reason := i.checkLifetime(c, body); reason != "" {
  		reasons = append(reasons, reason)
  	} else {
  		res.NonExpired = true
  	}
  
  	switch reason, err := i.checkSignature(c, &unwrapped); {
  	case err != nil:
  		return nil, err
  	case reason != "":
  		reasons = append(reasons, reason)
  	default:
  		res.Signed = true
  	}
  
  	res.InvalidityReason = strings.Join(reasons, "; ")
  	return res, nil
  }
docs: // InspectToken extracts as much information as possible from the token.
  //
  // Returns errors only if the inspection operation itself fails (i.e we can't
  // determine whether the token valid or not). If the given token is invalid,
  // returns Inspection object with details and nil error.