Merge "identity: Make SQL query order by recent dates first."
diff --git a/cmd/servicerunner/main.go b/cmd/servicerunner/main.go
index 397747d..8d243d8 100644
--- a/cmd/servicerunner/main.go
+++ b/cmd/servicerunner/main.go
@@ -22,6 +22,7 @@
 	"v.io/v23"
 	"v.io/v23/options"
 	"v.io/v23/rpc"
+	"v.io/v23/security"
 
 	"v.io/x/ref/envvar"
 	"v.io/x/ref/lib/signals"
@@ -127,7 +128,7 @@
 
 	lspec := v23.GetListenSpec(ctx)
 	lspec.Addrs = rpc.ListenAddrs{{"ws", "127.0.0.1:0"}}
-	proxyShutdown, proxyEndpoint, err := profiles.NewProxy(ctx, lspec, "test/proxy")
+	proxyShutdown, proxyEndpoint, err := profiles.NewProxy(ctx, lspec, security.AllowEveryone(), "test/proxy")
 	defer proxyShutdown()
 	vars["PROXY_NAME"] = proxyEndpoint.Name()
 
diff --git a/cmd/vdl/doc.go b/cmd/vdl/doc.go
index f51b087..e977881 100644
--- a/cmd/vdl/doc.go
+++ b/cmd/vdl/doc.go
@@ -85,7 +85,7 @@
    Same semantics as --go-out-dir but applies to js code generation.
  -js-relative-path-to-core=
    If set, this is the relative path from js-out-dir to the root of the JS core
- -lang=Go,Java
+ -lang=Go
    Comma-separated list of languages to generate, currently supporting
    Go,Java,Javascript
  -status=true
@@ -155,7 +155,7 @@
    Same semantics as --go-out-dir but applies to js code generation.
  -js-relative-path-to-core=
    If set, this is the relative path from js-out-dir to the root of the JS core
- -lang=Go,Java
+ -lang=Go
    Comma-separated list of languages to generate, currently supporting
    Go,Java,Javascript
  -status=true
diff --git a/cmd/vdl/main.go b/cmd/vdl/main.go
index 3f57f9c..6caf904 100644
--- a/cmd/vdl/main.go
+++ b/cmd/vdl/main.go
@@ -348,8 +348,8 @@
 		{"v.io", "io/v"},
 	}
 	optPathToJSCore string
-	// TODO(bjornick): Add javascript to the default gen langs.
-	optGenLangs = genLangs{vdltool.GenLanguageGo, vdltool.GenLanguageJava}
+	// Default to just running the go lang; other langs need special setup.
+	optGenLangs = genLangs{vdltool.GenLanguageGo}
 )
 
 // Root returns the root command for the VDL tool.
diff --git a/envvar/envvar.go b/envvar/envvar.go
index 37482d1..1f20fa7 100644
--- a/envvar/envvar.go
+++ b/envvar/envvar.go
@@ -60,11 +60,6 @@
 		if strings.HasPrefix(k, NamespacePrefix) && len(v) > 0 {
 			l = append(l, v)
 			m[k] = v
-		} else if strings.HasPrefix(k, "NAMESPACE_ROOT") && len(v) > 0 {
-			// TODO(ashankar): Remove this once the transition to
-			// the new enviornment variables is complete.
-			l = append(l, v)
-			m[k] = v
 		}
 	}
 	return m, l
diff --git a/lib/vdl/compile/const_test.go b/lib/vdl/compile/const_test.go
index a2ce72d..a3c0d20 100644
--- a/lib/vdl/compile/const_test.go
+++ b/lib/vdl/compile/const_test.go
@@ -611,41 +611,80 @@
 		"TypeObjectBool",
 		cp{{"a", `const Res = typeobject(bool)`, vdl.TypeObjectValue(vdl.BoolType), ""}}},
 	{
+		"TypeObjectBoolInvalid",
+		cp{{"a", `const Res = bool`, nil, "bool is a type"}}},
+	{
 		"TypeObjectString",
 		cp{{"a", `const Res = typeobject(string)`, vdl.TypeObjectValue(vdl.StringType), ""}}},
 	{
+		"TypeObjectStringInvalid",
+		cp{{"a", `const Res = string`, nil, "string is a type"}}},
+	{
 		"TypeObjectInt32",
 		cp{{"a", `const Res = typeobject(int32)`, vdl.TypeObjectValue(vdl.Int32Type), ""}}},
 	{
+		"TypeObjectInt32Invalid",
+		cp{{"a", `const Res = int32`, nil, "int32 is a type"}}},
+	{
 		"TypeObjectFloat32",
 		cp{{"a", `const Res = typeobject(float32)`, vdl.TypeObjectValue(vdl.Float32Type), ""}}},
 	{
+		"TypeObjectFloat32Invalid",
+		cp{{"a", `const Res = float32`, nil, "float32 is a type"}}},
+	{
 		"TypeObjectComplex64",
 		cp{{"a", `const Res = typeobject(complex64)`, vdl.TypeObjectValue(vdl.Complex64Type), ""}}},
 	{
+		"TypeObjectComplex64Invalid",
+		cp{{"a", `const Res = complex64`, nil, "complex64 is a type"}}},
+	{
 		"TypeObjectTypeObject",
 		cp{{"a", `const Res = typeobject(typeobject)`, vdl.TypeObjectValue(vdl.TypeObjectType), ""}}},
 	{
+		"TypeObjectTypeObjectInvalid",
+		cp{{"a", `const Res = typeobject`, nil, "syntax error"}}},
+	{
 		"TypeObjectList",
 		cp{{"a", `const Res = typeobject([]string)`, vdl.TypeObjectValue(vdl.ListType(vdl.StringType)), ""}}},
 	{
+		"TypeObjectListInvalid",
+		cp{{"a", `const Res = []string`, nil, `syntax error`}}},
+	{
 		"TypeObjectArray",
 		cp{{"a", `type T [3]int64; const Res = typeobject(T)`, vdl.TypeObjectValue(vdl.NamedType("p.kg/a.T", vdl.ArrayType(3, vdl.Int64Type))), ""}}},
 	{
+		"TypeObjectArrayInvalid",
+		cp{{"a", `const Res = [3]int64`, nil, `syntax error`}}},
+	{
 		"TypeObjectSet",
 		cp{{"a", `const Res = typeobject(set[string])`, vdl.TypeObjectValue(vdl.SetType(vdl.StringType)), ""}}},
 	{
+		"TypeObjectSetInvalid",
+		cp{{"a", `const Res = set[string]`, nil, `syntax error`}}},
+	{
 		"TypeObjectMap",
 		cp{{"a", `const Res = typeobject(map[string]int32)`, vdl.TypeObjectValue(vdl.MapType(vdl.StringType, vdl.Int32Type)), ""}}},
 	{
+		"TypeObjectMapInvalid",
+		cp{{"a", `const Res = map[string]int32`, nil, `syntax error`}}},
+	{
 		"TypeObjectStruct",
 		cp{{"a", `type A struct{X int64;Y string;Z bool}; const Res = typeobject(A)`, vdl.TypeObjectValue(makeStructType("p.kg/a.A")), ""}}},
 	{
+		"TypeObjectStructInvalid",
+		cp{{"a", `type A struct{X int64;Y string;Z bool}; const Res = A`, nil, `A is a type`}}},
+	{
 		"TypeObjectStructField",
 		cp{{"a", `type A struct{T typeobject}; const Res = A{typeobject(bool)}`, makeStructTypeObject("p.kg/a.A", vdl.BoolType), ""}}},
 	{
+		"TypeObjectStructFieldInvalid",
+		cp{{"a", `type A struct{T typeobject}; const Res = A{bool}`, nil, `bool is a type`}}},
+	{
 		"TypeObjectEnum",
 		cp{{"a", `type A enum{X;Y;Z}; const Res = typeobject(A)`, vdl.TypeObjectValue(vdl.NamedType("p.kg/a.A", vdl.EnumType("X", "Y", "Z"))), ""}}},
+	{
+		"TypeObjectEnumInvalid",
+		cp{{"a", `type A enum{X;Y;Z}; const Res = A`, nil, `A is a type`}}},
 
 	// Test named consts.
 	{
diff --git a/lib/vdl/compile/interface.go b/lib/vdl/compile/interface.go
index eae574b..fc3a161 100644
--- a/lib/vdl/compile/interface.go
+++ b/lib/vdl/compile/interface.go
@@ -184,8 +184,12 @@
 			continue // keep going to catch more errors
 		}
 		seen[parg.Name] = parg
-		if io == out && len(pargs) > 2 && parg.Name == "" {
-			id.env.Errorf(file, parg.Pos, "method %s out arg unnamed (must name all out args if there are more than 2)", method.Name)
+		switch {
+		case io == in && parg.Name == "":
+			id.env.Errorf(file, parg.Pos, "method %s in-arg unnamed (must name all in-args)", method.Name)
+			continue // keep going to catch more errors
+		case io == out && len(pargs) > 1 && parg.Name == "":
+			id.env.Errorf(file, parg.Pos, "method %s out-arg unnamed (must name all out-args if there are more than 1)", method.Name)
 			continue // keep going to catch more errors
 		}
 		if parg.Name != "" {
diff --git a/lib/vdl/compile/interface_test.go b/lib/vdl/compile/interface_test.go
index 1d2f8ac..0546e49 100644
--- a/lib/vdl/compile/interface_test.go
+++ b/lib/vdl/compile/interface_test.go
@@ -130,6 +130,16 @@
 		},
 		"",
 	}}},
+	{"NamedOutArg", ip{{"a", `type Res interface{NamedOutArg() (s string | error)}`,
+		&compile.Interface{
+			NamePos: np("Res"),
+			Methods: []*compile.Method{{
+				NamePos: np("NamedOutArg"),
+				OutArgs: []*compile.Field{{NamePos: np("s"), Type: vdl.StringType}},
+			}},
+		},
+		"",
+	}}},
 	{"Embed", ip{{"a", `type A interface{};type Res interface{A}`,
 		&compile.Interface{
 			NamePos: np("Res"),
@@ -167,4 +177,13 @@
 	{"UnmatchedEmbed", ip{{"a", `type A interface{};type Res interface{A.foobar}`, nil,
 		`\(\.foobar unmatched\)`,
 	}}},
+	{"NoErrorReturn", ip{{"a", `type Res interface{NoArgs()}`, nil,
+		`syntax error`,
+	}}},
+	{"UnnamedInArg", ip{{"a", `type Res interface{UnnamedInArg(string) error}`, nil,
+		`must name all in-args`,
+	}}},
+	{"UnnamedOutArgs", ip{{"a", `type Res interface{UnnamedOutArgs() (bool, string | error)}`, nil,
+		`must name all out-args if there are more than 1`,
+	}}},
 }
diff --git a/lib/vdl/testdata/arith/arith.vdl b/lib/vdl/testdata/arith/arith.vdl
index 294e95f..ef28a53 100644
--- a/lib/vdl/testdata/arith/arith.vdl
+++ b/lib/vdl/testdata/arith/arith.vdl
@@ -2,29 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Package arith is an example of an IdL definition in vanadium.  The syntax for
-// IdL files is similar to, but not identical to, Go.  Here are the main
-// concepts:
-//   * PACKAGES - Just like in Go you must define the package at the beginning
-//     of an IdL file, and everything defined in the file is part of this
-//     package.  By convention all files in the same dir should be in the same
-//     package.
-//   * IMPORTS - Just like in Go you can import other idl packages, and you may
-//     assign a local package name, or if unspecified the basename of the import
-//     path is used as the import package name.
-//   * DATA TYPES - Just like in Go you can define data types.  You get most of
-//     the primitives (int32, float64, string, etc), the "error" built-in, and a
-//     special "any" built-in described below.  In addition you can create
-//     composite types like arrays, structs, etc.
-//   * CONSTS - Just like in Go you can define constants, and numerics are
-//     "infinite precision" within expressions.  Unlike Go numerics must be
-//     typed to be used as const definitions or tags.
-//   * INTERFACES - Just like in Go you can define interface types, which are
-//     just a set of methods.  Interfaces can embed other interfaces.  Unlike
-//     Go, you cannot use an interface as a data type; interfaces are purely
-//     method sets.
-//   * ERRORS - Errors may be defined in IdL files, and unlike Go they work
-//     across separate address spaces.
+// Package arith is a vdl test package with imports.
 package arith
 
 // Test the import mechanism.
diff --git a/lib/vdl/testdata/arith/arith.vdl.go b/lib/vdl/testdata/arith/arith.vdl.go
index 3a1502e..c0cd823 100644
--- a/lib/vdl/testdata/arith/arith.vdl.go
+++ b/lib/vdl/testdata/arith/arith.vdl.go
@@ -5,29 +5,7 @@
 // This file was auto-generated by the vanadium vdl tool.
 // Source: arith.vdl
 
-// Package arith is an example of an IdL definition in vanadium.  The syntax for
-// IdL files is similar to, but not identical to, Go.  Here are the main
-// concepts:
-//   * PACKAGES - Just like in Go you must define the package at the beginning
-//     of an IdL file, and everything defined in the file is part of this
-//     package.  By convention all files in the same dir should be in the same
-//     package.
-//   * IMPORTS - Just like in Go you can import other idl packages, and you may
-//     assign a local package name, or if unspecified the basename of the import
-//     path is used as the import package name.
-//   * DATA TYPES - Just like in Go you can define data types.  You get most of
-//     the primitives (int32, float64, string, etc), the "error" built-in, and a
-//     special "any" built-in described below.  In addition you can create
-//     composite types like arrays, structs, etc.
-//   * CONSTS - Just like in Go you can define constants, and numerics are
-//     "infinite precision" within expressions.  Unlike Go numerics must be
-//     typed to be used as const definitions or tags.
-//   * INTERFACES - Just like in Go you can define interface types, which are
-//     just a set of methods.  Interfaces can embed other interfaces.  Unlike
-//     Go, you cannot use an interface as a data type; interfaces are purely
-//     method sets.
-//   * ERRORS - Errors may be defined in IdL files, and unlike Go they work
-//     across separate address spaces.
+// Package arith is a vdl test package with imports.
 package arith
 
 import (
diff --git a/profiles/internal/rpc/client.go b/profiles/internal/rpc/client.go
index 7827237..5995f66 100644
--- a/profiles/internal/rpc/client.go
+++ b/profiles/internal/rpc/client.go
@@ -166,9 +166,8 @@
 		return nil, suberr(verror.New(errClientCloseAlreadyCalled, ctx))
 	}
 	if othervc, exists := c.vcMap[vcKey]; exists {
+		go vc.Close(nil)
 		vc = othervc.vc
-		// TODO(ashankar,toddw): Figure out how to close up the VC that
-		// is discarded. vc.Close?
 	} else {
 		c.vcMap[vcKey] = &vcInfo{vc: vc, remoteEP: ep}
 	}
diff --git a/profiles/internal/rpc/server.go b/profiles/internal/rpc/server.go
index 102f82a..e89bfe9 100644
--- a/profiles/internal/rpc/server.go
+++ b/profiles/internal/rpc/server.go
@@ -34,6 +34,7 @@
 	"v.io/x/ref/profiles/internal/lib/publisher"
 	inaming "v.io/x/ref/profiles/internal/naming"
 	"v.io/x/ref/profiles/internal/rpc/stream"
+	"v.io/x/ref/profiles/internal/rpc/stream/manager"
 	"v.io/x/ref/profiles/internal/rpc/stream/vc"
 )
 
@@ -88,6 +89,7 @@
 	state             serverState          // track state of the server.
 	streamMgr         stream.Manager       // stream manager to listen for new flows.
 	publisher         publisher.Publisher  // publisher to publish mounttable mounts.
+	dc                vc.DischargeClient   // fetches discharges of blessings
 	listenerOpts      []stream.ListenerOpt // listener opts for Listen.
 	settingsPublisher *pubsub.Publisher    // pubsub publisher for dhcp
 	settingsName      string               // pubwsub stream name for dhcp
@@ -234,8 +236,8 @@
 	}
 	// Make dischargeExpiryBuffer shorter than the VC discharge buffer to ensure we have fetched
 	// the discharges by the time the VC asks for them.`
-	dc := InternalNewDischargeClient(ctx, client, dischargeExpiryBuffer-(5*time.Second))
-	s.listenerOpts = append(s.listenerOpts, dc)
+	s.dc = InternalNewDischargeClient(ctx, client, dischargeExpiryBuffer-(5*time.Second))
+	s.listenerOpts = append(s.listenerOpts, s.dc)
 	s.listenerOpts = append(s.listenerOpts, vc.DialContext{ctx})
 	blessingsStatsName := naming.Join(statsPrefix, "security", "blessings")
 	// TODO(caprita): revist printing the blessings with %s, and
@@ -464,7 +466,8 @@
 	if err != nil {
 		return nil, nil, verror.New(errFailedToResolveProxy, s.ctx, proxy, err)
 	}
-	ln, ep, err := s.streamMgr.Listen(inaming.Network, resolved, s.principal, s.blessings, s.listenerOpts...)
+	opts := append([]stream.ListenerOpt{proxyAuth{s}}, s.listenerOpts...)
+	ln, ep, err := s.streamMgr.Listen(inaming.Network, resolved, s.principal, s.blessings, opts...)
 	if err != nil {
 		return nil, nil, verror.New(errFailedToListenForProxy, s.ctx, resolved, err)
 	}
@@ -1243,7 +1246,6 @@
 		auth = security.DefaultAuthorizer()
 	}
 	if err := auth.Authorize(ctx, call); err != nil {
-		// TODO(ataly, ashankar): For privacy reasons, should we hide the authorizer error?
 		return verror.New(verror.ErrNoAccess, ctx, newErrBadAuth(ctx, call.Suffix(), call.Method(), err))
 	}
 	return nil
@@ -1334,3 +1336,46 @@
 	//nologcall
 	return fs.flow.RemoteEndpoint()
 }
+
+type proxyAuth struct {
+	s *server
+}
+
+func (a proxyAuth) RPCStreamListenerOpt() {}
+
+func (a proxyAuth) Login(proxy stream.Flow) (security.Blessings, []security.Discharge, error) {
+	// TODO(ashankar): Restore this block after figuring out flakiness in javascript-browser-integration tests.
+	// https://v.io/i/33
+	return security.Blessings{}, nil, nil
+	/*
+		var (
+			principal = a.s.principal
+			dc        = a.s.dc
+			ctx       = a.s.ctx
+		)
+		if principal == nil {
+			return security.Blessings{}, nil, nil
+		}
+		proxyNames, _ := security.RemoteBlessingNames(ctx, security.NewCall(&security.CallParams{
+			LocalPrincipal:   principal,
+			RemoteBlessings:  proxy.RemoteBlessings(),
+			RemoteDischarges: proxy.RemoteDischarges(),
+			RemoteEndpoint:   proxy.RemoteEndpoint(),
+			LocalEndpoint:    proxy.LocalEndpoint(),
+		}))
+		blessings := principal.BlessingStore().ForPeer(proxyNames...)
+		tpc := blessings.ThirdPartyCaveats()
+		if len(tpc) == 0 {
+			return blessings, nil, nil
+		}
+		// Ugh! Have to convert from proxyNames to BlessingPatterns
+		proxyPats := make([]security.BlessingPattern, len(proxyNames))
+		for idx, n := range proxyNames {
+			proxyPats[idx] = security.BlessingPattern(n)
+		}
+		discharges := dc.PrepareDischarges(ctx, tpc, security.DischargeImpetus{Server: proxyPats})
+		return blessings, discharges, nil
+	*/
+}
+
+var _ manager.ProxyAuthenticator = proxyAuth{}
diff --git a/profiles/internal/rpc/server_authorizer.go b/profiles/internal/rpc/server_authorizer.go
index fdccfc4..5478b29 100644
--- a/profiles/internal/rpc/server_authorizer.go
+++ b/profiles/internal/rpc/server_authorizer.go
@@ -50,8 +50,6 @@
 func newServerAuthorizer(pattern security.BlessingPattern, opts ...rpc.CallOpt) security.Authorizer {
 	auth := &serverAuthorizer{}
 	for _, o := range opts {
-		// TODO(ataly, ashankar): Consider creating an authorizer for each of the
-		// options below and then take the intersection of the authorizers.
 		switch v := o.(type) {
 		case options.ServerPublicKey:
 			auth.serverPublicKey = v.PublicKey
diff --git a/profiles/internal/rpc/stream/crypto/tls.go b/profiles/internal/rpc/stream/crypto/tls.go
index 8b371ab..cdb58de 100644
--- a/profiles/internal/rpc/stream/crypto/tls.go
+++ b/profiles/internal/rpc/stream/crypto/tls.go
@@ -36,13 +36,6 @@
 
 func (TLSClientSessionCache) RPCStreamVCOpt() {}
 
-// NewTLSClientSessionCache creates a new session cache.
-// TODO(ashankar): Remove this once go1.4 is released and tlsfork can be release, at that
-// point use crypto/tls.NewLRUClientSessionCache directly.
-func NewTLSClientSessionCache() TLSClientSessionCache {
-	return TLSClientSessionCache{tls.NewLRUClientSessionCache(-1)}
-}
-
 // NewTLSClient returns a Crypter implementation that uses TLS, assuming
 // handshaker was initiated by a client.
 func NewTLSClient(handshaker io.ReadWriteCloser, local, remote net.Addr, sessionCache TLSClientSessionCache, pool *iobuf.Pool) (Crypter, error) {
@@ -231,14 +224,10 @@
 	return c.tls.ConnectionState().TLSUnique
 }
 
-// TODO(ashankar): Get rid of TLS certificates completely after implementing an
-// anonymous key-exchange mechanism. See F.1.1.1 in RFC 5246.
-//
 // PEM-encoded certificates and keys used in the tests.
 // One way to generate them is:
 //   go run $GOROOT/src/pkg/crypto/tls/generate_cert.go  --host=localhost --duration=87600h --ecdsa-curve=P256
 // (This generates a self-signed certificate valid for 10 years)
-// (The --ecdsa-curve flag has not yet been submitted back to the Go repository)
 // which will create cert.pem and key.pem files.
 const (
 	serverCert = `
diff --git a/profiles/internal/rpc/stream/manager/listener.go b/profiles/internal/rpc/stream/manager/listener.go
index 3824089..2af4149 100644
--- a/profiles/internal/rpc/stream/manager/listener.go
+++ b/profiles/internal/rpc/stream/manager/listener.go
@@ -27,6 +27,16 @@
 	"v.io/x/ref/profiles/internal/rpc/stream"
 )
 
+// ProxyAuthenticator is a stream.ListenerOpt that is used when listening via a
+// proxy to authenticate with the proxy.
+type ProxyAuthenticator interface {
+	stream.ListenerOpt
+	// Login returns the Blessings (and the set of Discharges to make them
+	// valid) to send to the proxy. Typically, the proxy uses these to
+	// determine whether it wants to authorize use.
+	Login(proxy stream.Flow) (security.Blessings, []security.Discharge, error)
+}
+
 func reg(id, msg string) verror.IDAction {
 	return verror.Register(verror.ID(pkgPath+id), verror.NoRetry, msg)
 }
@@ -47,6 +57,7 @@
 	errAcceptFailed               = reg(".errAcceptFailed", "accept failed{:3}")
 	errFailedToEstablishVC        = reg(".errFailedToEstablishVC", "VC establishment with proxy failed{:_}")
 	errListenerAlreadyClosed      = reg(".errListenerAlreadyClosed", "listener already closed")
+	errRefusedProxyLogin          = reg(".errRefusedProxyLogin", "server did not want to listen via proxy{:_}")
 )
 
 // listener extends stream.Listener with a DebugString method.
@@ -288,12 +299,19 @@
 	vlog.VI(1).Infof("Connecting to proxy at %v", ln.proxyEP)
 	// Requires dialing a VC to the proxy, need to extract options from ln.opts to do so.
 	var dialOpts []stream.VCOpt
+	var auth ProxyAuthenticator
 	for _, opt := range opts {
-		if dopt, ok := opt.(stream.VCOpt); ok {
-			dialOpts = append(dialOpts, dopt)
+		switch v := opt.(type) {
+		case stream.VCOpt:
+			dialOpts = append(dialOpts, v)
+		case ProxyAuthenticator:
+			auth = v
 		}
 	}
-	// TODO(cnicolaou, ashankar): probably want to set a timeout here. (is this covered by opts?)
+	// TODO(cnicolaou, ashankar): probably want to set a timeout here. (is
+	// this covered by opts?)
+	// TODO(ashankar): Authorize the proxy server as well (similar to how
+	// clients authorize servers in RPCs).
 	vf, err := ln.manager.FindOrDialVIF(ln.proxyEP, principal, dialOpts...)
 	if err != nil {
 		return nil, nil, err
@@ -322,6 +340,12 @@
 	}
 	var request proxy.Request
 	var response proxy.Response
+	if auth != nil {
+		if request.Blessings, request.Discharges, err = auth.Login(flow); err != nil {
+			vf.StopAccepting()
+			return nil, nil, verror.New(stream.ErrSecurity, nil, verror.New(errRefusedProxyLogin, nil, err))
+		}
+	}
 	enc, err := vom.NewEncoder(flow)
 	if err != nil {
 		flow.Close()
diff --git a/profiles/internal/rpc/stream/manager/manager.go b/profiles/internal/rpc/stream/manager/manager.go
index 5fb6232..16e951a 100644
--- a/profiles/internal/rpc/stream/manager/manager.go
+++ b/profiles/internal/rpc/stream/manager/manager.go
@@ -22,7 +22,6 @@
 	"v.io/x/ref/lib/stats/counter"
 	inaming "v.io/x/ref/profiles/internal/naming"
 	"v.io/x/ref/profiles/internal/rpc/stream"
-	"v.io/x/ref/profiles/internal/rpc/stream/crypto"
 	"v.io/x/ref/profiles/internal/rpc/stream/vc"
 	"v.io/x/ref/profiles/internal/rpc/stream/vif"
 )
@@ -57,21 +56,19 @@
 func InternalNew(rid naming.RoutingID) stream.Manager {
 	statsPrefix := naming.Join("rpc", "stream", "routing-id", rid.String())
 	m := &manager{
-		rid:          rid,
-		vifs:         vif.NewSet(),
-		sessionCache: crypto.NewTLSClientSessionCache(),
-		listeners:    make(map[listener]bool),
-		statsPrefix:  statsPrefix,
-		killedConns:  stats.NewCounter(naming.Join(statsPrefix, "killed-connections")),
+		rid:         rid,
+		vifs:        vif.NewSet(),
+		listeners:   make(map[listener]bool),
+		statsPrefix: statsPrefix,
+		killedConns: stats.NewCounter(naming.Join(statsPrefix, "killed-connections")),
 	}
 	stats.NewStringFunc(naming.Join(m.statsPrefix, "debug"), m.DebugString)
 	return m
 }
 
 type manager struct {
-	rid          naming.RoutingID
-	vifs         *vif.Set
-	sessionCache crypto.TLSClientSessionCache
+	rid  naming.RoutingID
+	vifs *vif.Set
 
 	muListeners sync.Mutex
 	listeners   map[listener]bool // GUARDED_BY(muListeners)
@@ -160,7 +157,7 @@
 		if err != nil {
 			return nil, err
 		}
-		opts = append([]stream.VCOpt{m.sessionCache, vc.IdleTimeout{defaultIdleTimeout}}, opts...)
+		opts = append([]stream.VCOpt{vc.IdleTimeout{defaultIdleTimeout}}, opts...)
 		vc, err := vf.Dial(remote, principal, opts...)
 		if !retry || verror.ErrorID(err) != stream.ErrAborted.ID {
 			return vc, err
diff --git a/profiles/internal/rpc/stream/proxy/protocol.vdl b/profiles/internal/rpc/stream/proxy/protocol.vdl
index 087365f..da87aa0 100644
--- a/profiles/internal/rpc/stream/proxy/protocol.vdl
+++ b/profiles/internal/rpc/stream/proxy/protocol.vdl
@@ -4,6 +4,8 @@
 
 package proxy
 
+import "v.io/v23/security"
+
 // The proxy protocol is:
 // (1) Server establishes a VC to the proxy to register its routing id and authenticate.
 // (2) The server opens a flow and sends a "Request" message and waits for a "Response"
@@ -16,6 +18,11 @@
 // traffic intended for the server's RoutingId to the network connection
 // between the server and the proxy.
 type Request struct {
+  // Blessings of the server that wishes to be proxied.
+  // Used to authorize the use of the proxy.
+  Blessings security.WireBlessings
+  // Discharges required to make Blessings valid.
+  Discharges []security.WireDischarge
 }
 
 // Response is sent by the proxy to the server after processing Request.
diff --git a/profiles/internal/rpc/stream/proxy/protocol.vdl.go b/profiles/internal/rpc/stream/proxy/protocol.vdl.go
index ff7c265..e02fe6b 100644
--- a/profiles/internal/rpc/stream/proxy/protocol.vdl.go
+++ b/profiles/internal/rpc/stream/proxy/protocol.vdl.go
@@ -10,12 +10,20 @@
 import (
 	// VDL system imports
 	"v.io/v23/vdl"
+
+	// VDL user imports
+	"v.io/v23/security"
 )
 
 // Request is the message sent by a server to request that the proxy route
 // traffic intended for the server's RoutingId to the network connection
 // between the server and the proxy.
 type Request struct {
+	// Blessings of the server that wishes to be proxied.
+	// Used to authorize the use of the proxy.
+	Blessings security.Blessings
+	// Discharges required to make Blessings valid.
+	Discharges []security.Discharge
 }
 
 func (Request) __VDLReflect(struct {
diff --git a/profiles/internal/rpc/stream/proxy/proxy.go b/profiles/internal/rpc/stream/proxy/proxy.go
index 3944e13..9cf4d92 100644
--- a/profiles/internal/rpc/stream/proxy/proxy.go
+++ b/profiles/internal/rpc/stream/proxy/proxy.go
@@ -7,6 +7,7 @@
 import (
 	"fmt"
 	"net"
+	"reflect"
 	"sync"
 	"time"
 
@@ -77,10 +78,12 @@
 // Proxy routes virtual circuit (VC) traffic between multiple underlying
 // network connections.
 type Proxy struct {
+	ctx        *context.T
 	ln         net.Listener
 	rid        naming.RoutingID
 	principal  security.Principal
 	blessings  security.Blessings
+	authorizer security.Authorizer
 	mu         sync.RWMutex
 	servers    *servermap
 	processes  map[*process]struct{}
@@ -182,17 +185,17 @@
 }
 
 // New creates a new Proxy that listens for network connections on the provided
-// (network, address) pair and routes VC traffic between accepted connections.
-// TODO(mattr): This should take a ListenSpec instead of network, address, and
-// pubAddress.  However using a ListenSpec requires a great deal of supporting
-// code that should be refactored out of v.io/x/ref/profiles/internal/rpc/server.go.
-func New(ctx *context.T, spec rpc.ListenSpec, names ...string) (shutdown func(), endpoint naming.Endpoint, err error) {
+// ListenSpec and routes VC traffic between accepted connections.
+//
+// Servers wanting to "listen through the proxy" will only be allowed to do so
+// if the blessings they present are accepted to the provided authorization
+// policy (authorizer).
+func New(ctx *context.T, spec rpc.ListenSpec, authorizer security.Authorizer, names ...string) (shutdown func(), endpoint naming.Endpoint, err error) {
 	rid, err := naming.NewRoutingID()
 	if err != nil {
 		return nil, nil, err
 	}
-
-	proxy, err := internalNew(rid, v23.GetPrincipal(ctx), spec)
+	proxy, err := internalNew(rid, ctx, spec, authorizer)
 	if err != nil {
 		return nil, nil, err
 	}
@@ -221,7 +224,7 @@
 	return shutdown, proxy.endpoint(), nil
 }
 
-func internalNew(rid naming.RoutingID, principal security.Principal, spec rpc.ListenSpec) (*Proxy, error) {
+func internalNew(rid naming.RoutingID, ctx *context.T, spec rpc.ListenSpec, authorizer security.Authorizer) (*Proxy, error) {
 	if len(spec.Addrs) == 0 {
 		return nil, verror.New(stream.ErrProxy, nil, verror.New(errEmptyListenSpec, nil))
 	}
@@ -245,19 +248,23 @@
 		ln.Close()
 		return nil, verror.New(stream.ErrProxy, nil, verror.New(errNoAccessibleAddresses, nil, ln.Addr().String()))
 	}
-
+	if authorizer == nil {
+		authorizer = security.DefaultAuthorizer()
+	}
 	proxy := &Proxy{
-		ln:        ln,
-		rid:       rid,
-		servers:   &servermap{m: make(map[naming.RoutingID]*server)},
-		processes: make(map[*process]struct{}),
+		ctx:        ctx,
+		ln:         ln,
+		rid:        rid,
+		authorizer: authorizer,
+		servers:    &servermap{m: make(map[naming.RoutingID]*server)},
+		processes:  make(map[*process]struct{}),
 		// TODO(cnicolaou): should use all of the available addresses
 		pubAddress: pub[0].String(),
-		principal:  principal,
+		principal:  v23.GetPrincipal(ctx),
 		statsName:  naming.Join("rpc", "proxy", "routing-id", rid.String(), "debug"),
 	}
-	if principal != nil {
-		proxy.blessings = principal.BlessingStore().Default()
+	if proxy.principal != nil {
+		proxy.blessings = proxy.principal.BlessingStore().Default()
 	}
 	stats.NewStringFunc(proxy.statsName, proxy.debugString)
 
@@ -341,6 +348,8 @@
 		response.Error = verror.New(stream.ErrProxy, nil, verror.New(errVomDecoder, nil, err))
 	} else if err := dec.Decode(&request); err != nil {
 		response.Error = verror.New(stream.ErrProxy, nil, verror.New(errNoRequest, nil, err))
+	} else if err := p.authorize(server.VC, request); err != nil {
+		response.Error = err
 	} else if err := p.servers.Add(server); err != nil {
 		response.Error = verror.Convert(verror.ErrUnknown, nil, err)
 	} else {
@@ -379,6 +388,30 @@
 	server.Close(nil)
 }
 
+func (p *Proxy) authorize(vc *vc.VC, request Request) error {
+	var dmap map[string]security.Discharge
+	if len(request.Discharges) > 0 {
+		dmap := make(map[string]security.Discharge)
+		for _, d := range request.Discharges {
+			dmap[d.ID()] = d
+		}
+	}
+	// Blessings must be bound to the same public key as the VC.
+	// (Repeating logic in the RPC server authorization code).
+	if got, want := request.Blessings.PublicKey(), vc.RemoteBlessings().PublicKey(); !request.Blessings.IsZero() && !reflect.DeepEqual(got, want) {
+		return verror.New(verror.ErrNoAccess, nil, fmt.Errorf("malformed request: Blessings sent in proxy.Request are bound to public key %v and not %v", got, want))
+	}
+	return p.authorizer.Authorize(p.ctx, security.NewCall(&security.CallParams{
+		LocalPrincipal:   vc.LocalPrincipal(),
+		LocalBlessings:   vc.LocalBlessings(),
+		RemoteBlessings:  request.Blessings,
+		LocalEndpoint:    vc.LocalEndpoint(),
+		RemoteEndpoint:   vc.RemoteEndpoint(),
+		LocalDischarges:  vc.LocalDischarges(),
+		RemoteDischarges: dmap,
+	}))
+}
+
 func (p *Proxy) routeCounters(process *process, counters message.Counters) {
 	// Since each VC can be routed to a different process, split up the
 	// Counters into one message per VC.
diff --git a/profiles/internal/rpc/stream/proxy/proxy_test.go b/profiles/internal/rpc/stream/proxy/proxy_test.go
index c84e7cf..cffa224 100644
--- a/profiles/internal/rpc/stream/proxy/proxy_test.go
+++ b/profiles/internal/rpc/stream/proxy/proxy_test.go
@@ -13,10 +13,10 @@
 	"testing"
 	"time"
 
-	"v.io/x/lib/vlog"
-
 	"v.io/v23"
+	"v.io/v23/context"
 	"v.io/v23/naming"
+	"v.io/v23/security"
 	"v.io/v23/verror"
 
 	_ "v.io/x/ref/profiles"
@@ -33,12 +33,10 @@
 //go:generate v23 test generate
 
 func TestProxy(t *testing.T) {
-	ctx, shutdown := test.InitForTest()
+	ctx, shutdown := v23Init()
 	defer shutdown()
 
-	pproxy := testutil.NewPrincipal("proxy")
-
-	_, shutdown, proxyEp, err := proxy.InternalNew(naming.FixedRoutingID(0xbbbbbbbbbbbbbbbb), pproxy, v23.GetListenSpec(ctx))
+	_, shutdown, proxyEp, err := proxy.InternalNew(naming.FixedRoutingID(0xbbbbbbbbbbbbbbbb), ctx, security.AllowEveryone())
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -46,8 +44,6 @@
 	principal := testutil.NewPrincipal("test")
 	blessings := principal.BlessingStore().Default()
 
-	vlog.Infof("PROXYEP: %s", proxyEp)
-
 	// Create the stream.Manager for the server.
 	server1 := manager.InternalNew(naming.FixedRoutingID(0x1111111111111111))
 	defer server1.Shutdown()
@@ -102,12 +98,60 @@
 	}
 }
 
-func TestDuplicateRoutingID(t *testing.T) {
-	ctx, shutdown := test.InitForTest()
+func TestProxyAuthorization(t *testing.T) {
+	ctx, shutdown := v23Init()
 	defer shutdown()
 
-	pproxy := testutil.NewPrincipal("proxy")
-	_, shutdown, proxyEp, err := proxy.InternalNew(naming.FixedRoutingID(0xbbbbbbbbbbbbbbbb), pproxy, v23.GetListenSpec(ctx))
+	_, shutdown, proxyEp, err := proxy.InternalNew(naming.FixedRoutingID(0xbbbbbbbbbbbbbbbb), ctx, testAuth{"alice", "carol"})
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer shutdown()
+
+	var (
+		alice = testutil.NewPrincipal("alice")
+		bob   = testutil.NewPrincipal("bob")
+		carol = testutil.NewPrincipal("carol")
+		dave  = testutil.NewPrincipal("dave")
+	)
+	// Make the proxy recognize "alice", "bob" and "carol", but not "dave"
+	v23.GetPrincipal(ctx).AddToRoots(alice.BlessingStore().Default())
+	v23.GetPrincipal(ctx).AddToRoots(bob.BlessingStore().Default())
+	v23.GetPrincipal(ctx).AddToRoots(carol.BlessingStore().Default())
+
+	testcases := []struct {
+		p  security.Principal
+		ok bool
+	}{
+		{alice, true}, // passes the auth policy
+		{bob, false},  // recognized, but not included in auth policy
+		{carol, true}, // passes the auth policy
+		{dave, false}, // not recognized, thus doesn't pass the auth policy
+	}
+	for idx, test := range testcases {
+		server := manager.InternalNew(naming.FixedRoutingID(uint64(idx)))
+		_, ep, err := server.Listen(proxyEp.Network(), proxyEp.String(), test.p, test.p.BlessingStore().Default(), proxyAuth{test.p})
+		if (err == nil) != test.ok {
+			t.Errorf("Got ep=%v, err=%v - wanted error:%v", ep, err, !test.ok)
+		}
+		server.Shutdown()
+	}
+}
+
+type proxyAuth struct {
+	p security.Principal
+}
+
+func (proxyAuth) RPCStreamListenerOpt() {}
+func (a proxyAuth) Login(stream.Flow) (security.Blessings, []security.Discharge, error) {
+	return a.p.BlessingStore().Default(), nil, nil
+}
+
+func TestDuplicateRoutingID(t *testing.T) {
+	ctx, shutdown := v23Init()
+	defer shutdown()
+
+	_, shutdown, proxyEp, err := proxy.InternalNew(naming.FixedRoutingID(0xbbbbbbbbbbbbbbbb), ctx, security.AllowEveryone())
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -137,11 +181,11 @@
 }
 
 func TestProxyAuthentication(t *testing.T) {
-	ctx, shutdown := test.InitForTest()
+	ctx, shutdown := v23Init()
 	defer shutdown()
 
-	pproxy := testutil.NewPrincipal("proxy")
-	_, shutdown, proxyEp, err := proxy.InternalNew(naming.FixedRoutingID(0xbbbbbbbbbbbbbbbb), pproxy, v23.GetListenSpec(ctx))
+	pproxy := v23.GetPrincipal(ctx)
+	_, shutdown, proxyEp, err := proxy.InternalNew(naming.FixedRoutingID(0xbbbbbbbbbbbbbbbb), ctx, security.AllowEveryone())
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -168,16 +212,15 @@
 }
 
 func TestServerBlessings(t *testing.T) {
-	ctx, shutdown := test.InitForTest()
+	ctx, shutdown := v23Init()
 	defer shutdown()
 
 	var (
-		pproxy  = testutil.NewPrincipal("proxy")
 		pserver = testutil.NewPrincipal("server")
 		pclient = testutil.NewPrincipal("client")
 	)
 
-	_, shutdown, proxyEp, err := proxy.InternalNew(naming.FixedRoutingID(0xbbbbbbbbbbbbbbbb), pproxy, v23.GetListenSpec(ctx))
+	_, shutdown, proxyEp, err := proxy.InternalNew(naming.FixedRoutingID(0xbbbbbbbbbbbbbbbb), ctx, security.AllowEveryone())
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -221,11 +264,10 @@
 }
 
 func TestHostPort(t *testing.T) {
-	ctx, shutdown := test.InitForTest()
+	ctx, shutdown := v23Init()
 	defer shutdown()
 
-	pproxy := testutil.NewPrincipal("proxy")
-	_, shutdown, proxyEp, err := proxy.InternalNew(naming.FixedRoutingID(0xbbbbbbbbbbbbbbbb), pproxy, v23.GetListenSpec(ctx))
+	_, shutdown, proxyEp, err := proxy.InternalNew(naming.FixedRoutingID(0xbbbbbbbbbbbbbbbb), ctx, security.AllowEveryone())
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -244,11 +286,10 @@
 }
 
 func TestClientBecomesServer(t *testing.T) {
-	ctx, shutdown := test.InitForTest()
+	ctx, shutdown := v23Init()
 	defer shutdown()
 
-	pproxy := testutil.NewPrincipal("proxy")
-	_, shutdown, proxyEp, err := proxy.InternalNew(naming.FixedRoutingID(0xbbbbbbbbbbbbbbbb), pproxy, v23.GetListenSpec(ctx))
+	_, shutdown, proxyEp, err := proxy.InternalNew(naming.FixedRoutingID(0xbbbbbbbbbbbbbbbb), ctx, security.AllowEveryone())
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -302,7 +343,7 @@
 }
 
 func testProxyIdleTimeout(t *testing.T, testServer bool) {
-	ctx, shutdown := test.InitForTest()
+	ctx, shutdown := v23Init()
 	defer shutdown()
 
 	const (
@@ -313,7 +354,6 @@
 	)
 
 	var (
-		pproxy  = testutil.NewPrincipal("proxy")
 		pserver = testutil.NewPrincipal("server")
 		pclient = testutil.NewPrincipal("client")
 
@@ -329,7 +369,7 @@
 	// Pause the idle timers.
 	triggerTimers := vif.SetFakeTimers()
 
-	Proxy, shutdown, proxyEp, err := proxy.InternalNew(naming.FixedRoutingID(0xbbbbbbbbbbbbbbbb), pproxy, v23.GetListenSpec(ctx))
+	Proxy, shutdown, proxyEp, err := proxy.InternalNew(naming.FixedRoutingID(0xbbbbbbbbbbbbbbbb), ctx, security.AllowEveryone())
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -444,3 +484,26 @@
 		buf.Write(tmp[:n])
 	}
 }
+
+func v23Init() (*context.T, func()) {
+	ctx, shutdown := test.InitForTest()
+	ctx, err := v23.WithPrincipal(ctx, testutil.NewPrincipal("proxy"))
+	if err != nil {
+		panic(err)
+	}
+	return ctx, shutdown
+}
+
+type testAuth []string
+
+func (l testAuth) Authorize(ctx *context.T, call security.Call) error {
+	remote, rejected := security.RemoteBlessingNames(ctx, call)
+	for _, n := range remote {
+		for _, a := range l {
+			if n == a {
+				return nil
+			}
+		}
+	}
+	return fmt.Errorf("%v not in authorized set of %v (rejected: %v)", remote, l, rejected)
+}
diff --git a/profiles/internal/rpc/stream/proxy/testutil_test.go b/profiles/internal/rpc/stream/proxy/testutil_test.go
index 8a1568c..727b8a5 100644
--- a/profiles/internal/rpc/stream/proxy/testutil_test.go
+++ b/profiles/internal/rpc/stream/proxy/testutil_test.go
@@ -5,15 +5,16 @@
 package proxy
 
 import (
+	"v.io/v23"
+	"v.io/v23/context"
 	"v.io/v23/naming"
-	"v.io/v23/rpc"
 	"v.io/v23/security"
 )
 
 // These are the internal functions only for use in the proxy_test package.
 
-func InternalNew(rid naming.RoutingID, p security.Principal, spec rpc.ListenSpec) (*Proxy, func(), naming.Endpoint, error) {
-	proxy, err := internalNew(rid, p, spec)
+func InternalNew(rid naming.RoutingID, ctx *context.T, auth security.Authorizer) (*Proxy, func(), naming.Endpoint, error) {
+	proxy, err := internalNew(rid, ctx, v23.GetListenSpec(ctx), auth)
 	if err != nil {
 		return nil, nil, nil, err
 	}
diff --git a/profiles/internal/rpc/test/proxy_test.go b/profiles/internal/rpc/test/proxy_test.go
index e6bd616..4316f55 100644
--- a/profiles/internal/rpc/test/proxy_test.go
+++ b/profiles/internal/rpc/test/proxy_test.go
@@ -56,7 +56,7 @@
 	expected := len(args)
 
 	listenSpec := rpc.ListenSpec{Addrs: rpc.ListenAddrs{{"tcp", "127.0.0.1:0"}}}
-	proxyShutdown, proxyEp, err := proxy.New(ctx, listenSpec)
+	proxyShutdown, proxyEp, err := proxy.New(ctx, listenSpec, security.AllowEveryone())
 	if err != nil {
 		fmt.Fprintf(stderr, "%s\n", verror.DebugString(err))
 		return err
diff --git a/profiles/proxy.go b/profiles/proxy.go
index 0a12b4e..9b4a350 100644
--- a/profiles/proxy.go
+++ b/profiles/proxy.go
@@ -8,12 +8,16 @@
 	"v.io/v23/context"
 	"v.io/v23/naming"
 	"v.io/v23/rpc"
+	"v.io/v23/security"
 
 	"v.io/x/ref/profiles/internal/rpc/stream/proxy"
 )
 
 // NewProxy creates a new Proxy that listens for network connections on the provided
 // (network, address) pair and routes VC traffic between accepted connections.
-func NewProxy(ctx *context.T, spec rpc.ListenSpec, names ...string) (shutdown func(), endpoint naming.Endpoint, err error) {
-	return proxy.New(ctx, spec, names...)
+//
+// auth encapsulates the authorization policy of the proxy - which
+// servers it is willing to proxy for.
+func NewProxy(ctx *context.T, spec rpc.ListenSpec, auth security.Authorizer, names ...string) (shutdown func(), endpoint naming.Endpoint, err error) {
+	return proxy.New(ctx, spec, auth, names...)
 }
diff --git a/profiles/roaming/proxy.go b/profiles/roaming/proxy.go
index 845ad11..5590a7c 100644
--- a/profiles/roaming/proxy.go
+++ b/profiles/roaming/proxy.go
@@ -8,12 +8,16 @@
 	"v.io/v23/context"
 	"v.io/v23/naming"
 	"v.io/v23/rpc"
+	"v.io/v23/security"
 
 	"v.io/x/ref/profiles/internal/rpc/stream/proxy"
 )
 
 // NewProxy creates a new Proxy that listens for network connections on the provided
 // (network, address) pair and routes VC traffic between accepted connections.
-func NewProxy(ctx *context.T, spec rpc.ListenSpec, names ...string) (shutdown func(), endpoint naming.Endpoint, err error) {
-	return proxy.New(ctx, spec, names...)
+//
+// auth encapsulates the authorization policy of the proxy - which
+// servers it is willing to proxy for.
+func NewProxy(ctx *context.T, spec rpc.ListenSpec, auth security.Authorizer, names ...string) (shutdown func(), endpoint naming.Endpoint, err error) {
+	return proxy.New(ctx, spec, auth, names...)
 }
diff --git a/profiles/static/proxy.go b/profiles/static/proxy.go
index a398460..8693142 100644
--- a/profiles/static/proxy.go
+++ b/profiles/static/proxy.go
@@ -8,12 +8,16 @@
 	"v.io/v23/context"
 	"v.io/v23/naming"
 	"v.io/v23/rpc"
+	"v.io/v23/security"
 
 	"v.io/x/ref/profiles/internal/rpc/stream/proxy"
 )
 
 // NewProxy creates a new Proxy that listens for network connections on the provided
 // (network, address) pair and routes VC traffic between accepted connections.
-func NewProxy(ctx *context.T, spec rpc.ListenSpec, names ...string) (shutdown func(), endpoint naming.Endpoint, err error) {
-	return proxy.New(ctx, spec, names...)
+//
+// auth encapsulates the authorization policy of the proxy - which
+// servers it is willing to proxy for.
+func NewProxy(ctx *context.T, spec rpc.ListenSpec, auth security.Authorizer, names ...string) (shutdown func(), endpoint naming.Endpoint, err error) {
+	return proxy.New(ctx, spec, auth, names...)
 }
diff --git a/services/agent/agentd/main.go b/services/agent/agentd/main.go
index fa4b7d4..afb1f70 100644
--- a/services/agent/agentd/main.go
+++ b/services/agent/agentd/main.go
@@ -47,6 +47,8 @@
 	// agent should restart it.  Consider changing this to use the unix
 	// socket for this purpose.
 	restartExitCode = flag.String("restart-exit-code", "", "If non-empty, will restart the command when it exits, provided that the command's exit code matches the value of this flag.  The value must be an integer, or an integer preceded by '!' (in which case all exit codes except the flag will trigger a restart.")
+
+	newname = flag.String("new-principal-blessing-name", "", "If creating a new principal (--v23.credentials does not exist), then have it blessed with this name.")
 )
 
 func main() {
@@ -203,7 +205,11 @@
 	if err != nil {
 		return nil, pass, err
 	}
-	vsecurity.InitDefaultBlessings(p, "agent_principal")
+	name := *newname
+	if len(name) == 0 {
+		name = "agent_principal"
+	}
+	vsecurity.InitDefaultBlessings(p, name)
 	return p, pass, nil
 }
 
diff --git a/services/device/deviced/server.go b/services/device/deviced/server.go
index 26e38d1..61e8773 100644
--- a/services/device/deviced/server.go
+++ b/services/device/deviced/server.go
@@ -124,7 +124,7 @@
 	// method that calls Stop on the app cycle manager (e.g. the Stop RPC)
 	// will precipitate an immediate process exit.
 	shutdownChan := signals.ShutdownOnSignals(ctx)
-	stop, err := starter.Start(ctx, starter.Args{Namespace: ns, Device: dev, MountGlobalNamespaceInLocalNamespace: true, Proxy: proxy})
+	_, stop, err := starter.Start(ctx, starter.Args{Namespace: ns, Device: dev, MountGlobalNamespaceInLocalNamespace: true, Proxy: proxy})
 	if err != nil {
 		return err
 	}
diff --git a/services/device/internal/impl/debug_perms_test.go b/services/device/internal/impl/debug_perms_test.go
index 5179c07..f8a14f9 100644
--- a/services/device/internal/impl/debug_perms_test.go
+++ b/services/device/internal/impl/debug_perms_test.go
@@ -45,7 +45,7 @@
 	// Set up the device manager.
 	dmh := servicetest.RunCommand(t, sh, nil, deviceManagerCmd, "dm", root, helperPath, "unused_app_repo_name", "unused_curr_link")
 	servicetest.ReadPID(t, dmh)
-	claimDevice(t, ctx, "dm", "mydevice", noPairingToken)
+	claimDevice(t, ctx, "claimable", "dm", "mydevice", noPairingToken)
 
 	// Create the local server that the app uses to let us know it's ready.
 	pingCh, cleanup := setupPingServer(t, ctx)
@@ -209,7 +209,7 @@
 	hjCtx := ctxWithNewPrincipal(t, selfCtx, idp, "hackerjoe")
 
 	// Bob claims the device manager.
-	claimDevice(t, bobCtx, "dm", "mydevice", noPairingToken)
+	claimDevice(t, bobCtx, "claimable", "dm", "mydevice", noPairingToken)
 
 	// Create some globbing test vectors.
 	dmGlobtests := []globTestVector{
diff --git a/services/device/internal/impl/device_installer.go b/services/device/internal/impl/device_installer.go
index 4e3f7ca..8846d4d 100644
--- a/services/device/internal/impl/device_installer.go
+++ b/services/device/internal/impl/device_installer.go
@@ -78,8 +78,7 @@
 	return nil
 }
 
-// TODO(caprita,ashankar): Remove VEYRON_.* and NAMESPACE_ROOT.*.
-var allowedVarsRE = regexp.MustCompile("V23_.*|VEYRON_.*|NAMESPACE_ROOT.*|PAUSE_BEFORE_STOP|TMPDIR")
+var allowedVarsRE = regexp.MustCompile("V23_.*|PAUSE_BEFORE_STOP|TMPDIR")
 
 var deniedVarsRE = regexp.MustCompile("V23_EXEC_VERSION")
 
diff --git a/services/device/internal/impl/impl_test.go b/services/device/internal/impl/impl_test.go
index 4b2cdf4..1109c71 100644
--- a/services/device/internal/impl/impl_test.go
+++ b/services/device/internal/impl/impl_test.go
@@ -174,7 +174,7 @@
 	// method that calls Stop on the app cycle manager (e.g. the Stop RPC)
 	// will precipitate an immediate process exit.
 	shutdownChan := signals.ShutdownOnSignals(ctx)
-	stop, err := starter.Start(ctx, starter.Args{
+	claimableName, stop, err := starter.Start(ctx, starter.Args{
 		Namespace: starter.NamespaceArgs{
 			ListenSpec: rpc.ListenSpec{Addrs: rpc.ListenAddrs{{"tcp", "127.0.0.1:0"}}},
 		},
@@ -196,6 +196,15 @@
 		return err
 	}
 	defer stop()
+	// Update the namespace roots to remove the server blessing from the
+	// endpoints.  This is needed to be able to publish into the 'global'
+	// mounttable before we have compatible credentials.
+	ctx, err = setNamespaceRootsForUnclaimedDevice(ctx)
+	if err != nil {
+		return err
+	}
+	// Manually mount the claimable service in the 'global' mounttable.
+	v23.GetNamespace(ctx).Mount(ctx, "claimable", claimableName, 0)
 	fmt.Fprintf(stdout, "ready:%d\n", os.Getpid())
 
 	<-shutdownChan
@@ -414,9 +423,9 @@
 	}()
 
 	servicetest.ReadPID(t, dmh)
+	resolve(t, ctx, "claimable", 1)
 	// Brand new device manager must be claimed first.
-	claimDevice(t, ctx, "factoryDM", "mydevice", noPairingToken)
-
+	claimDevice(t, ctx, "claimable", "factoryDM", "mydevice", noPairingToken)
 	// Simulate an invalid envelope in the application repository.
 	*envelope = envelopeFromShell(sh, dmPauseBeforeStopEnv, deviceManagerCmd, "bogus", dmArgs...)
 
@@ -651,7 +660,7 @@
 	// don't worry about its application envelope and current link.
 	dmh := servicetest.RunCommand(t, sh, nil, deviceManagerCmd, "dm", root, helperPath, "unused_app_repo_name", "unused_curr_link")
 	servicetest.ReadPID(t, dmh)
-	claimDevice(t, ctx, "dm", "mydevice", noPairingToken)
+	claimDevice(t, ctx, "claimable", "dm", "mydevice", noPairingToken)
 
 	// Create the local server that the app uses to let us know it's ready.
 	pingCh, cleanup := setupPingServer(t, ctx)
@@ -980,9 +989,9 @@
 	//installAppExpectError(t, octx, impl.ErrUnclaimedDevice.ID)
 
 	// Claim the device with an incorrect pairing token should fail.
-	claimDeviceExpectError(t, claimantCtx, "dm", "mydevice", "badtoken", impl.ErrInvalidPairingToken.ID)
+	claimDeviceExpectError(t, claimantCtx, "claimable", "mydevice", "badtoken", impl.ErrInvalidPairingToken.ID)
 	// But succeed with a valid pairing token
-	claimDevice(t, claimantCtx, "dm", "mydevice", pairingToken)
+	claimDevice(t, claimantCtx, "claimable", "dm", "mydevice", pairingToken)
 
 	// Installation should succeed since claimantRT is now the "owner" of
 	// the devicemanager.
@@ -1054,13 +1063,12 @@
 	*envelope = envelopeFromShell(sh, nil, appCmd, "google naps")
 
 	// On an unclaimed device manager, there will be no AccessLists.
-	deviceStub := device.DeviceClient("dm/device")
-	if _, _, err := deviceStub.GetPermissions(selfCtx); err == nil {
+	if _, _, err := device.DeviceClient("claimable").GetPermissions(selfCtx); err == nil {
 		t.Fatalf("GetPermissions should have failed but didn't.")
 	}
 
 	// Claim the devicemanager as "root/self/mydevice"
-	claimDevice(t, selfCtx, "dm", "mydevice", noPairingToken)
+	claimDevice(t, selfCtx, "claimable", "dm", "mydevice", noPairingToken)
 	expectedAccessList := make(access.Permissions)
 	for _, tag := range access.AllTypicalTags() {
 		expectedAccessList[string(tag)] = access.AccessList{In: []security.BlessingPattern{"root/$", "root/self/$", "root/self/mydevice/$"}}
@@ -1073,6 +1081,7 @@
 	// manager version.
 	md5hash := md5.Sum(b.Bytes())
 	expectedVersion := hex.EncodeToString(md5hash[:])
+	deviceStub := device.DeviceClient("dm/device")
 	perms, version, err := deviceStub.GetPermissions(selfCtx)
 	if err != nil {
 		t.Fatal(err)
@@ -1151,7 +1160,7 @@
 	}
 	dms := expect.NewSession(t, stdout, servicetest.ExpectTimeout)
 	servicetest.ReadPID(t, dms)
-	claimDevice(t, ctx, "dm", "mydevice", noPairingToken)
+	claimDevice(t, ctx, "claimable", "dm", "mydevice", noPairingToken)
 	revertDeviceExpectError(t, ctx, "dm", impl.ErrUpdateNoOp.ID) // No previous version available.
 
 	// Stop the device manager.
@@ -1208,7 +1217,7 @@
 	*envelope = envelopeFromShell(sh, nil, appCmd, "google naps", "appV1")
 
 	// Device must be claimed before applications can be installed.
-	claimDevice(t, ctx, "dm", "mydevice", noPairingToken)
+	claimDevice(t, ctx, "claimable", "dm", "mydevice", noPairingToken)
 	// Install the app.
 	appID := installApp(t, ctx)
 	install1ID := path.Base(appID)
@@ -1363,7 +1372,7 @@
 		},
 	}
 	// Device must be claimed before apps can be installed.
-	claimDevice(t, ctx, "dm", "mydevice", noPairingToken)
+	claimDevice(t, ctx, "claimable", "dm", "mydevice", noPairingToken)
 	// Install the app.
 	appID := installApp(t, ctx, packages)
 
@@ -1452,17 +1461,17 @@
 	defer syscall.Kill(pid, syscall.SIGINT)
 	defer verifyNoRunningProcesses(t)
 
-	deviceStub := device.DeviceClient("dm/device")
 	// Attempt to list associations on the device manager without having
 	// claimed it.
-	if list, err := deviceStub.ListAssociations(otherCtx); err == nil {
+	if list, err := device.DeviceClient("claimable").ListAssociations(otherCtx); err == nil {
 		t.Fatalf("ListAssociations should fail on unclaimed device manager but did not: (%v, %v)", list, err)
 	}
 
 	// self claims the device manager.
-	claimDevice(t, selfCtx, "dm", "alice", noPairingToken)
+	claimDevice(t, selfCtx, "claimable", "dm", "alice", noPairingToken)
 
 	vlog.VI(2).Info("Verify that associations start out empty.")
+	deviceStub := device.DeviceClient("dm/device")
 	listAndVerifyAssociations(t, selfCtx, deviceStub, []device.Association(nil))
 
 	if err := deviceStub.AssociateAccount(selfCtx, []string{"root/self", "root/other"}, "alice_system_account"); err != nil {
@@ -1552,7 +1561,7 @@
 	defer syscall.Kill(pid, syscall.SIGINT)
 	defer verifyNoRunningProcesses(t)
 	// Claim the devicemanager with selfCtx as root/self/alice
-	claimDevice(t, selfCtx, "dm", "alice", noPairingToken)
+	claimDevice(t, selfCtx, "claimable", "dm", "alice", noPairingToken)
 
 	deviceStub := device.DeviceClient("dm/device")
 
@@ -1733,7 +1742,7 @@
 	dmh := servicetest.RunCommand(t, sh, nil, deviceManagerCmd, "dm", root, helperPath, "unused_app_repo_name", "unused_curr_link")
 	pid := servicetest.ReadPID(t, dmh)
 	defer syscall.Kill(pid, syscall.SIGINT)
-	claimDevice(t, ctx, "dm", "mydevice", noPairingToken)
+	claimDevice(t, ctx, "claimable", "dm", "mydevice", noPairingToken)
 
 	publisher, err := v23.GetPrincipal(ctx).BlessSelf("publisher")
 	if err != nil {
diff --git a/services/device/internal/impl/instance_reaping_test.go b/services/device/internal/impl/instance_reaping_test.go
index b8b70dd..2ff35fa 100644
--- a/services/device/internal/impl/instance_reaping_test.go
+++ b/services/device/internal/impl/instance_reaping_test.go
@@ -30,7 +30,7 @@
 	// don't worry about its application envelope and current link.
 	dmh := servicetest.RunCommand(t, sh, nil, deviceManagerCmd, "dm", root, helperPath, "unused_app_repo_name", "unused_curr_link")
 	servicetest.ReadPID(t, dmh)
-	claimDevice(t, ctx, "dm", "mydevice", noPairingToken)
+	claimDevice(t, ctx, "claimable", "dm", "mydevice", noPairingToken)
 
 	// Create the local server that the app uses to let us know it's ready.
 	pingCh, cleanup := setupPingServer(t, ctx)
@@ -110,7 +110,7 @@
 
 	dmh := servicetest.RunCommand(t, sh, dmEnv, deviceManagerCmd, "dm", root, helperPath, "unused_app_repo_name", "unused_curr_link")
 	servicetest.ReadPID(t, dmh)
-	claimDevice(t, ctx, "dm", "mydevice", noPairingToken)
+	claimDevice(t, ctx, "claimable", "dm", "mydevice", noPairingToken)
 
 	// Create the local server that the app uses to let us know it's ready.
 	pingCh, cleanup := setupPingServer(t, ctx)
diff --git a/services/device/internal/impl/util_test.go b/services/device/internal/impl/util_test.go
index 909a58a..c043873 100644
--- a/services/device/internal/impl/util_test.go
+++ b/services/device/internal/impl/util_test.go
@@ -94,25 +94,24 @@
 	return device.DeviceClient(deviceName)
 }
 
-func claimDevice(t *testing.T, ctx *context.T, name, extension, pairingToken string) {
+func claimDevice(t *testing.T, ctx *context.T, claimableName, deviceName, extension, pairingToken string) {
 	// Setup blessings to be granted to the claimed device
 	g := &granter{extension: extension}
 	s := options.SkipServerEndpointAuthorization{}
 	// Call the Claim RPC: Skip server authorization because the unclaimed
 	// device presents nothing that can be used to recognize it.
-	if err := device.ClaimableClient(name).Claim(ctx, pairingToken, g, s); err != nil {
-		t.Fatalf(testutil.FormatLogLine(2, "%q.Claim(%q) failed: %v [%v]", name, pairingToken, verror.ErrorID(err), err))
+	if err := device.ClaimableClient(claimableName).Claim(ctx, pairingToken, g, s); err != nil {
+		t.Fatalf(testutil.FormatLogLine(2, "%q.Claim(%q) failed: %v [%v]", claimableName, pairingToken, verror.ErrorID(err), err))
 	}
 	// Wait for the device to remount itself with the device service after
 	// being claimed.
-	// (Detected by the next claim failing with an error other than
-	// AlreadyClaimed)
 	start := time.Now()
 	for {
-		if err := device.ClaimableClient(name).Claim(ctx, pairingToken, g, s); verror.ErrorID(err) != impl.ErrDeviceAlreadyClaimed.ID {
+		_, err := v23.GetNamespace(ctx).Resolve(ctx, deviceName)
+		if err == nil {
 			return
 		}
-		vlog.VI(4).Infof("Claimable server at %q has not stopped yet", name)
+		vlog.VI(4).Infof("Resolve(%q) failed: %v", err)
 		time.Sleep(time.Millisecond)
 		if elapsed := time.Since(start); elapsed > time.Minute {
 			t.Fatalf("Device hasn't remounted itself in %v since it was claimed", elapsed)
@@ -630,3 +629,24 @@
 		t.Errorf("device manager incorrectly terminating with child processes still running")
 	}
 }
+
+func setNamespaceRootsForUnclaimedDevice(ctx *context.T) (*context.T, error) {
+	origroots := v23.GetNamespace(ctx).Roots()
+	roots := make([]string, len(origroots))
+	for i, orig := range origroots {
+		addr, suffix := naming.SplitAddressName(orig)
+		origep, err := v23.NewEndpoint(addr)
+		if err != nil {
+			return nil, err
+		}
+		ep := naming.FormatEndpoint(
+			origep.Addr().Network(),
+			origep.Addr().String(),
+			origep.RoutingID(),
+			naming.ServesMountTable(origep.ServesMountTable()))
+		roots[i] = naming.JoinAddressName(ep, suffix)
+	}
+	vlog.Infof("Changing namespace roots from %v to %v", origroots, roots)
+	ctx, _, err := v23.WithNewNamespace(ctx, roots...)
+	return ctx, err
+}
diff --git a/services/device/internal/starter/starter.go b/services/device/internal/starter/starter.go
index 646beff..50a2e9b 100644
--- a/services/device/internal/starter/starter.go
+++ b/services/device/internal/starter/starter.go
@@ -25,6 +25,7 @@
 	"v.io/v23/context"
 	"v.io/v23/naming"
 	"v.io/v23/rpc"
+	"v.io/v23/security"
 	"v.io/v23/verror"
 	"v.io/x/lib/vlog"
 )
@@ -32,14 +33,14 @@
 const pkgPath = "v.io/x/ref/services/device/internal/starter"
 
 var (
-	errCantSaveInfo       = verror.Register(pkgPath+".errCantSaveInfo", verror.NoRetry, "{1:}{2:} failed to save info{:_}")
-	errBadPort            = verror.Register(pkgPath+".errBadPort", verror.NoRetry, "{1:}{2:} invalid port{:_}")
-	errCantCreateProxy    = verror.Register(pkgPath+".errCantCreateProxy", verror.NoRetry, "{1:}{2:} Failed to create proxy{:_}")
-	errCantCreateEndpoint = verror.Register(pkgPath+".errCantCreateEndpoint", verror.NoRetry, "{1:}{2:} failed to create endpoint from namespace root {3}{:_}")
+	errCantSaveInfo      = verror.Register(pkgPath+".errCantSaveInfo", verror.NoRetry, "{1:}{2:} failed to save info{:_}")
+	errBadPort           = verror.Register(pkgPath+".errBadPort", verror.NoRetry, "{1:}{2:} invalid port{:_}")
+	errCantCreateProxy   = verror.Register(pkgPath+".errCantCreateProxy", verror.NoRetry, "{1:}{2:} Failed to create proxy{:_}")
+	errNoEndpointToClaim = verror.Register(pkgPath+".errNoEndpointToClaim", verror.NoRetry, "{1:}{2:} failed to find an endpoint for claiming{:_}")
 )
 
 type NamespaceArgs struct {
-	Name            string         // Name to publish the mounttable service under.
+	Name            string         // Name to publish the mounttable service under (after claiming).
 	ListenSpec      rpc.ListenSpec // ListenSpec for the server.
 	PermissionsFile string         // Path to the Permissions file used by the mounttable.
 	PersistenceDir  string         // Path to the directory holding persistent acls.
@@ -50,7 +51,7 @@
 }
 
 type DeviceArgs struct {
-	Name            string         // Name to publish the device service under.
+	Name            string         // Name to publish the device service under (after claiming).
 	ListenSpec      rpc.ListenSpec // ListenSpec for the device server.
 	ConfigState     *config.State  // Configuration for the device.
 	TestMode        bool           // Whether the device is running in test mode or not.
@@ -81,12 +82,13 @@
 
 // Start creates servers for the mounttable and device services and links them together.
 //
-// Returns the callback to be invoked to shutdown the services on success, or
-// an error on failure.
-func Start(ctx *context.T, args Args) (func(), error) {
+// Returns the object name for the claimable service (empty if already claimed),
+// a callback to be invoked to shutdown the services on success, or an error on
+// failure.
+func Start(ctx *context.T, args Args) (string, func(), error) {
 	// Is this binary compatible with the state on disk?
 	if err := impl.CheckCompatibility(args.Device.ConfigState.Root); err != nil {
-		return nil, err
+		return "", nil, err
 	}
 	// In test mode, we skip writing the info file to disk, and we skip
 	// attempting to start the claimable service: the device must have been
@@ -94,7 +96,8 @@
 	// NewClaimableDispatcher needlessly prints a perms signature
 	// verification error to the logs.
 	if args.Device.TestMode {
-		return startClaimedDevice(ctx, args)
+		cleanup, err := startClaimedDevice(ctx, args)
+		return "", cleanup, err
 	}
 
 	// TODO(caprita): use some mechanism (a file lock or presence of entry
@@ -104,7 +107,7 @@
 		Pid: os.Getpid(),
 	}
 	if err := impl.SaveManagerInfo(filepath.Join(args.Device.ConfigState.Root, "device-manager"), mi); err != nil {
-		return nil, verror.New(errCantSaveInfo, ctx, err)
+		return "", nil, verror.New(errCantSaveInfo, ctx, err)
 	}
 
 	// If the device has not yet been claimed, start the mounttable and
@@ -115,26 +118,23 @@
 	if claimable == nil {
 		// Device has already been claimed, bypass claimable service
 		// stage.
-		return startClaimedDevice(ctx, args)
+		cleanup, err := startClaimedDevice(ctx, args)
+		return "", cleanup, err
 	}
-	stopClaimable, err := startClaimableDevice(ctx, claimable, args)
+	epName, stopClaimable, err := startClaimableDevice(ctx, claimable, args)
 	if err != nil {
-		return nil, err
+		return "", nil, err
 	}
 	stop := make(chan struct{})
 	stopped := make(chan struct{})
 	go waitToBeClaimedAndStartClaimedDevice(ctx, stopClaimable, claimed, stop, stopped, args)
-	return func() {
+	return epName, func() {
 		close(stop)
 		<-stopped
 	}, nil
 }
 
-func startClaimableDevice(ctx *context.T, dispatcher rpc.Dispatcher, args Args) (func(), error) {
-	ctx, err := setNamespaceRootsForUnclaimedDevice(ctx)
-	if err != nil {
-		return nil, err
-	}
+func startClaimableDevice(ctx *context.T, dispatcher rpc.Dispatcher, args Args) (string, func(), error) {
 	// TODO(caprita,ashankar): We create a context with a new stream manager
 	// that we can cancel once the device has been claimed. This gets around
 	// the following issue: if we publish the claimable server to the local
@@ -147,43 +147,37 @@
 	// gets confused trying to reuse the old connection and doesn't attempt
 	// to create a new connection).  We should get to the bottom of it.
 	ctx, cancel := context.WithCancel(ctx)
+	var err error
 	if ctx, err = v23.WithNewStreamManager(ctx); err != nil {
 		cancel()
-		return nil, err
-	}
-	mtName, stopMT, err := startMounttable(ctx, args.Namespace)
-	if err != nil {
-		cancel()
-		return nil, err
+		return "", nil, err
 	}
 	server, err := v23.NewServer(ctx)
 	if err != nil {
-		stopMT()
 		cancel()
-		return nil, err
+		return "", nil, err
 	}
 	shutdown := func() {
 		vlog.Infof("Stopping claimable server...")
 		server.Stop()
 		vlog.Infof("Stopped claimable server.")
-		stopMT()
 		cancel()
 	}
 	endpoints, err := server.Listen(args.Device.ListenSpec)
 	if err != nil {
 		shutdown()
-		return nil, err
+		return "", nil, err
 	}
-	claimableServerName := args.Device.name(mtName)
-	if err := server.ServeDispatcher(claimableServerName, dispatcher); err != nil {
+	if err := server.ServeDispatcher("", dispatcher); err != nil {
 		shutdown()
-		return nil, err
+		return "", nil, err
 	}
 	publicKey, err := v23.GetPrincipal(ctx).PublicKey().MarshalBinary()
 	if err != nil {
 		shutdown()
-		return nil, err
+		return "", nil, err
 	}
+	var epName string
 	if args.Device.ListenSpec.Proxy != "" {
 		for {
 			p := server.Status().Proxies
@@ -192,13 +186,19 @@
 				time.Sleep(time.Second)
 				continue
 			}
-			vlog.Infof("Proxied address: %s", p[0].Endpoint.Name())
+			epName = p[0].Endpoint.Name()
+			vlog.Infof("Proxied address: %s", epName)
 			break
 		}
+	} else {
+		if len(endpoints) == 0 {
+			return "", nil, verror.New(errNoEndpointToClaim, ctx, err)
+		}
+		epName = endpoints[0].Name()
 	}
-	vlog.Infof("Unclaimed device manager (%v) published as %v with public_key: %s", endpoints[0].Name(), claimableServerName, base64.URLEncoding.EncodeToString(publicKey))
+	vlog.Infof("Unclaimed device manager (%v) with public_key: %s", epName, base64.URLEncoding.EncodeToString(publicKey))
 	vlog.FlushLog()
-	return shutdown, nil
+	return epName, shutdown, nil
 }
 
 func waitToBeClaimedAndStartClaimedDevice(ctx *context.T, stopClaimable func(), claimed, stop <-chan struct{}, stopped chan<- struct{}, args Args) {
@@ -283,7 +283,9 @@
 	// under.
 	ls := v23.GetListenSpec(ctx)
 	ls.Addrs = rpc.ListenAddrs{{protocol, addr}}
-	shutdown, ep, err := roaming.NewProxy(ctx, ls)
+	// TODO(ashankar): Revisit this choice of security.AllowEveryone
+	// See: https://v.io/i/387
+	shutdown, ep, err := roaming.NewProxy(ctx, ls, security.AllowEveryone())
 	if err != nil {
 		return nil, verror.New(errCantCreateProxy, ctx, err)
 	}
@@ -369,43 +371,3 @@
 		}(root)
 	}
 }
-
-// Unclaimed devices typically have Principals that recognize no other
-// authoritative public keys than their own. As a result, they will fail to
-// authorize any other services.
-//
-// With no information to authenticate or authorize peers (including the
-// mounttable at the namespace root), this unclaimed device manager will be
-// unable to make any outgoing RPCs.
-//
-// As a workaround, reconfigure it to "authorize any root mounttable" by
-// removing references to the expected blessings of the namespace root.  This
-// will allow the unclaimed device manager to mount itself.
-//
-// TODO(ashankar,caprita): The more secure fix would be to ensure that an
-// unclaimed device is configured to recognize the blessings presented by the
-// mounttable it is configured to talk to. Of course, if the root mounttable is
-// "discovered" as opposed to "configured", then this new device will have to
-// return to either not mounting itself (and being claimed via some discovery
-// protocol like mdns or bluetooth) or ignoring the blessings of the namespace
-// root.
-func setNamespaceRootsForUnclaimedDevice(ctx *context.T) (*context.T, error) {
-	origroots := v23.GetNamespace(ctx).Roots()
-	roots := make([]string, len(origroots))
-	for i, orig := range origroots {
-		addr, suffix := naming.SplitAddressName(orig)
-		origep, err := v23.NewEndpoint(addr)
-		if err != nil {
-			return nil, verror.New(errCantCreateEndpoint, ctx, orig, err)
-		}
-		ep := naming.FormatEndpoint(
-			origep.Addr().Network(),
-			origep.Addr().String(),
-			origep.RoutingID(),
-			naming.ServesMountTable(origep.ServesMountTable()))
-		roots[i] = naming.JoinAddressName(ep, suffix)
-	}
-	vlog.Infof("Changing namespace roots from %v to %v", origroots, roots)
-	ctx, _, err := v23.WithNewNamespace(ctx, roots...)
-	return ctx, err
-}
diff --git a/services/device/mgmt_v23_test.go b/services/device/mgmt_v23_test.go
index 1b09af6..b5b9e29 100644
--- a/services/device/mgmt_v23_test.go
+++ b/services/device/mgmt_v23_test.go
@@ -170,6 +170,36 @@
 
 	deviceScript.Start(deviceScriptArguments...).WaitOrDie(os.Stdout, os.Stderr)
 	deviceScript.Start("start").WaitOrDie(os.Stdout, os.Stderr)
+	// Grab the endpoint for the claimable service from the device manager's
+	// log.
+	dmLog := filepath.Join(dmInstallDir, "dmroot/device-manager/logs/deviced.INFO")
+	var claimableEP string
+	expiry := time.Now().Add(30 * time.Second)
+	for {
+		if time.Now().After(expiry) {
+			i.Fatalf("Timed out looking for claimable endpoint in %v", dmLog)
+		}
+		startLog, err := ioutil.ReadFile(dmLog)
+		if err != nil {
+			i.Logf("Couldn't read log %v: %v", dmLog, err)
+			time.Sleep(time.Second)
+			continue
+		}
+		re := regexp.MustCompile(`Unclaimed device manager \((.*)\)`)
+		matches := re.FindSubmatch(startLog)
+		if len(matches) == 0 {
+			i.Logf("Couldn't find match in %v [%v]", dmLog, startLog)
+			time.Sleep(time.Second)
+			continue
+		}
+		if len(matches) != 2 {
+			i.Fatalf("Wrong match in %v (%d) %v", dmLog, len(matches), string(matches[0]))
+		}
+		claimableEP = string(matches[1])
+		break
+	}
+	// Claim the device as "root/alice/myworkstation".
+	deviceBin.Start("claim", claimableEP, "myworkstation")
 
 	resolve := func(name string) string {
 		resolver := func() (interface{}, error) {
@@ -186,32 +216,10 @@
 		}
 		return i.WaitFor(resolver, 100*time.Millisecond, time.Minute).(string)
 	}
+
+	// Wait for the device manager to publish its mount table entry.
 	mtEP := resolve(mtName)
 
-	// Verify that device manager's mounttable is published under the expected
-	// name (hostname).
-	if got := namespaceBin.Run("glob", mtName); len(got) == 0 {
-		i.Fatalf("glob failed for %q", mtName)
-	}
-
-	// Claim the device as "root/alice/myworkstation".
-	deviceBin.Start("claim", mtName+"/devmgr/device", "myworkstation")
-
-	resolveChange := func(name, old string) string {
-		resolver := func() (interface{}, error) {
-			inv := namespaceBin.Start("resolve", name)
-			defer inv.Wait(nil, os.Stderr)
-			if r := strings.TrimRight(inv.Output(), "\n"); len(r) > 0 && r != old {
-				return r, nil
-			}
-			return nil, nil
-		}
-		return i.WaitFor(resolver, 100*time.Millisecond, time.Minute).(string)
-	}
-
-	// Wait for the device manager to update its mount table entry.
-	mtEP = resolveChange(mtName, mtEP)
-
 	if withSuid {
 		deviceBin.Start("associate", "add", mtName+"/devmgr/device", appUserFlag, "root/alice")
 
@@ -355,6 +363,17 @@
 
 	// Update the device manager.
 	deviceBin.Run("update", mtName+"/devmgr/device")
+	resolveChange := func(name, old string) string {
+		resolver := func() (interface{}, error) {
+			inv := namespaceBin.Start("resolve", name)
+			defer inv.Wait(nil, os.Stderr)
+			if r := strings.TrimRight(inv.Output(), "\n"); len(r) > 0 && r != old {
+				return r, nil
+			}
+			return nil, nil
+		}
+		return i.WaitFor(resolver, 100*time.Millisecond, time.Minute).(string)
+	}
 	mtEP = resolveChange(mtName, mtEP)
 
 	// Verify that device manager's mounttable is still published under the
diff --git a/services/identity/internal/dischargerlib/discharger.go b/services/identity/internal/dischargerlib/discharger.go
index 4fb6d48..d1d401e 100644
--- a/services/identity/internal/dischargerlib/discharger.go
+++ b/services/identity/internal/dischargerlib/discharger.go
@@ -37,8 +37,6 @@
 // discharges using the MintDischarge on the principal receiving the RPC.
 //
 // Discharges are valid for 15 minutes.
-// TODO(ashankar,ataly): Parameterize this? Make it easier for clients to add
-// caveats on the discharge?
 func NewDischarger() discharger.DischargerServerMethods {
 	return dischargerd{}
 }
diff --git a/services/proxy/proxyd/main.go b/services/proxy/proxyd/main.go
index d9114eb..f40b042 100644
--- a/services/proxy/proxyd/main.go
+++ b/services/proxy/proxyd/main.go
@@ -7,15 +7,17 @@
 package main
 
 import (
+	"bytes"
+	"encoding/json"
 	"flag"
 	"fmt"
 	"net/http"
-	_ "net/http/pprof"
 	"time"
 
 	"v.io/v23"
 	"v.io/v23/rpc"
 	"v.io/v23/security"
+	"v.io/v23/security/access"
 	"v.io/x/lib/vlog"
 
 	"v.io/x/ref/lib/signals"
@@ -26,6 +28,7 @@
 	pubAddress  = flag.String("published-address", "", "deprecated - the proxy now uses listenspecs and the address chooser mechanism")
 	healthzAddr = flag.String("healthz-address", "", "Network address on which the HTTP healthz server runs. It is intended to be used with a load balancer. The load balancer must be able to reach this address in order to verify that the proxy server is running")
 	name        = flag.String("name", "", "Name to mount the proxy as")
+	acl         = flag.String("access-list", "", "Blessings that are authorized to listen via the proxy. JSON-encoded representation of access.AccessList. An empty string implies the default authorization policy.")
 )
 
 func main() {
@@ -39,7 +42,23 @@
 	if listenSpec.Proxy != "" {
 		vlog.Fatalf("proxyd cannot listen through another proxy")
 	}
-	proxyShutdown, proxyEndpoint, err := static.NewProxy(ctx, listenSpec, *name)
+	var authorizer security.Authorizer
+	if len(*acl) > 0 {
+		var list access.AccessList
+		if err := json.NewDecoder(bytes.NewBufferString(*acl)).Decode(&list); err != nil {
+			vlog.Fatalf("invalid --access-list: %v", err)
+		}
+		// Always add ourselves, for the the reserved methods server
+		// started below.
+		list.In = append(list.In, security.DefaultBlessingPatterns(v23.GetPrincipal(ctx))...)
+		vlog.Infof("Using access list to control proxy use: %v", list)
+		authorizer = list
+		// See https://v.io/i/33
+		// Remove this line
+		authorizer = security.AllowEveryone()
+	}
+
+	proxyShutdown, proxyEndpoint, err := static.NewProxy(ctx, listenSpec, authorizer, *name)
 	if err != nil {
 		vlog.Fatal(err)
 	}
diff --git a/services/proxy/proxyd/proxyd_v23_test.go b/services/proxy/proxyd/proxyd_v23_test.go
index 2e4d4e0..e58c90d 100644
--- a/services/proxy/proxyd/proxyd_v23_test.go
+++ b/services/proxy/proxyd/proxyd_v23_test.go
@@ -42,7 +42,7 @@
 	)
 	// Start proxyd
 	proxyd.WithStartOpts(proxyd.StartOpts().WithCustomCredentials(proxydCreds)).
-		Start("--v23.tcp.address=127.0.0.1:0", "--name="+proxyName)
+		Start("--v23.tcp.address=127.0.0.1:0", "--name="+proxyName, "--access-list", "{\"In\":[\"root/server\"]}")
 	// Start the server that only listens via the proxy
 	if _, err := t.Shell().StartWithOpts(
 		t.Shell().DefaultStartOpts().WithCustomCredentials(serverCreds),
diff --git a/services/wspr/internal/app/app_test.go b/services/wspr/internal/app/app_test.go
index 6e14735..e259890 100644
--- a/services/wspr/internal/app/app_test.go
+++ b/services/wspr/internal/app/app_test.go
@@ -316,7 +316,7 @@
 		return nil, fmt.Errorf("unable to start mounttable: %v", err)
 	}
 	proxySpec := rpc.ListenSpec{Addrs: rpc.ListenAddrs{{"tcp", "127.0.0.1:0"}}}
-	proxyShutdown, proxyEndpoint, err := profiles.NewProxy(ctx, proxySpec)
+	proxyShutdown, proxyEndpoint, err := profiles.NewProxy(ctx, proxySpec, security.AllowEveryone())
 	if err != nil {
 		return nil, fmt.Errorf("unable to start proxy: %v", err)
 	}
diff --git a/services/wspr/internal/app/controller.vdl b/services/wspr/internal/app/controller.vdl
index 0f6be7c..68376f0 100644
--- a/services/wspr/internal/app/controller.vdl
+++ b/services/wspr/internal/app/controller.vdl
@@ -29,13 +29,13 @@
 	BlessingsDebugString(handle principal.BlessingsHandle) (string | error)
 	// Bless binds extensions of blessings held by this principal to
 	// another principal (represented by its public key).
-	Bless(publicKey string, blessingHandle principal.BlessingsHandle, extension string, caveat []security.Caveat) (string, principal.BlessingsHandle | error)
+	Bless(publicKey string, handle principal.BlessingsHandle, extension string, caveat []security.Caveat) (publicKeyOut string, handleOut principal.BlessingsHandle | error)
 	// BlessSelf creates a blessing with the provided name for this principal.
-	BlessSelf(name string, caveats []security.Caveat) (string, principal.BlessingsHandle | error)
+	BlessSelf(name string, caveats []security.Caveat) (publicKeyOut string, handleOut principal.BlessingsHandle | error)
 	// PutToBlessingStore puts the specified blessing to the blessing store under the provided pattern.
-	PutToBlessingStore(blessingHandle principal.BlessingsHandle, pattern security.BlessingPattern) (?principal.JsBlessings | error)
+	PutToBlessingStore(handle principal.BlessingsHandle, pattern security.BlessingPattern) (?principal.JsBlessings | error)
 	// AddToRoots adds the provided blessing as a root.
-	AddToRoots(blessingHandle principal.BlessingsHandle) error
+	AddToRoots(handle principal.BlessingsHandle) error
 
 	// RemoteBlessings fetches the remote blessings for a given name and method.
 	RemoteBlessings(name, method string) ([]string | error)
diff --git a/services/wspr/internal/app/controller.vdl.go b/services/wspr/internal/app/controller.vdl.go
index fe63c72..f8b6c0d 100644
--- a/services/wspr/internal/app/controller.vdl.go
+++ b/services/wspr/internal/app/controller.vdl.go
@@ -38,13 +38,13 @@
 	BlessingsDebugString(ctx *context.T, handle principal.BlessingsHandle, opts ...rpc.CallOpt) (string, error)
 	// Bless binds extensions of blessings held by this principal to
 	// another principal (represented by its public key).
-	Bless(ctx *context.T, publicKey string, blessingHandle principal.BlessingsHandle, extension string, caveat []security.Caveat, opts ...rpc.CallOpt) (string, principal.BlessingsHandle, error)
+	Bless(ctx *context.T, publicKey string, handle principal.BlessingsHandle, extension string, caveat []security.Caveat, opts ...rpc.CallOpt) (publicKeyOut string, handleOut principal.BlessingsHandle, err error)
 	// BlessSelf creates a blessing with the provided name for this principal.
-	BlessSelf(ctx *context.T, name string, caveats []security.Caveat, opts ...rpc.CallOpt) (string, principal.BlessingsHandle, error)
+	BlessSelf(ctx *context.T, name string, caveats []security.Caveat, opts ...rpc.CallOpt) (publicKeyOut string, handleOut principal.BlessingsHandle, err error)
 	// PutToBlessingStore puts the specified blessing to the blessing store under the provided pattern.
-	PutToBlessingStore(ctx *context.T, blessingHandle principal.BlessingsHandle, pattern security.BlessingPattern, opts ...rpc.CallOpt) (*principal.JsBlessings, error)
+	PutToBlessingStore(ctx *context.T, handle principal.BlessingsHandle, pattern security.BlessingPattern, opts ...rpc.CallOpt) (*principal.JsBlessings, error)
 	// AddToRoots adds the provided blessing as a root.
-	AddToRoots(ctx *context.T, blessingHandle principal.BlessingsHandle, opts ...rpc.CallOpt) error
+	AddToRoots(ctx *context.T, handle principal.BlessingsHandle, opts ...rpc.CallOpt) error
 	// RemoteBlessings fetches the remote blessings for a given name and method.
 	RemoteBlessings(ctx *context.T, name string, method string, opts ...rpc.CallOpt) ([]string, error)
 	// Signature fetches the signature for a given name.
@@ -152,13 +152,13 @@
 	BlessingsDebugString(ctx *context.T, call rpc.ServerCall, handle principal.BlessingsHandle) (string, error)
 	// Bless binds extensions of blessings held by this principal to
 	// another principal (represented by its public key).
-	Bless(ctx *context.T, call rpc.ServerCall, publicKey string, blessingHandle principal.BlessingsHandle, extension string, caveat []security.Caveat) (string, principal.BlessingsHandle, error)
+	Bless(ctx *context.T, call rpc.ServerCall, publicKey string, handle principal.BlessingsHandle, extension string, caveat []security.Caveat) (publicKeyOut string, handleOut principal.BlessingsHandle, err error)
 	// BlessSelf creates a blessing with the provided name for this principal.
-	BlessSelf(ctx *context.T, call rpc.ServerCall, name string, caveats []security.Caveat) (string, principal.BlessingsHandle, error)
+	BlessSelf(ctx *context.T, call rpc.ServerCall, name string, caveats []security.Caveat) (publicKeyOut string, handleOut principal.BlessingsHandle, err error)
 	// PutToBlessingStore puts the specified blessing to the blessing store under the provided pattern.
-	PutToBlessingStore(ctx *context.T, call rpc.ServerCall, blessingHandle principal.BlessingsHandle, pattern security.BlessingPattern) (*principal.JsBlessings, error)
+	PutToBlessingStore(ctx *context.T, call rpc.ServerCall, handle principal.BlessingsHandle, pattern security.BlessingPattern) (*principal.JsBlessings, error)
 	// AddToRoots adds the provided blessing as a root.
-	AddToRoots(ctx *context.T, call rpc.ServerCall, blessingHandle principal.BlessingsHandle) error
+	AddToRoots(ctx *context.T, call rpc.ServerCall, handle principal.BlessingsHandle) error
 	// RemoteBlessings fetches the remote blessings for a given name and method.
 	RemoteBlessings(ctx *context.T, call rpc.ServerCall, name string, method string) ([]string, error)
 	// Signature fetches the signature for a given name.
@@ -322,14 +322,14 @@
 			Name: "Bless",
 			Doc:  "// Bless binds extensions of blessings held by this principal to\n// another principal (represented by its public key).",
 			InArgs: []rpc.ArgDesc{
-				{"publicKey", ``},      // string
-				{"blessingHandle", ``}, // principal.BlessingsHandle
-				{"extension", ``},      // string
-				{"caveat", ``},         // []security.Caveat
+				{"publicKey", ``}, // string
+				{"handle", ``},    // principal.BlessingsHandle
+				{"extension", ``}, // string
+				{"caveat", ``},    // []security.Caveat
 			},
 			OutArgs: []rpc.ArgDesc{
-				{"", ``}, // string
-				{"", ``}, // principal.BlessingsHandle
+				{"publicKeyOut", ``}, // string
+				{"handleOut", ``},    // principal.BlessingsHandle
 			},
 		},
 		{
@@ -340,16 +340,16 @@
 				{"caveats", ``}, // []security.Caveat
 			},
 			OutArgs: []rpc.ArgDesc{
-				{"", ``}, // string
-				{"", ``}, // principal.BlessingsHandle
+				{"publicKeyOut", ``}, // string
+				{"handleOut", ``},    // principal.BlessingsHandle
 			},
 		},
 		{
 			Name: "PutToBlessingStore",
 			Doc:  "// PutToBlessingStore puts the specified blessing to the blessing store under the provided pattern.",
 			InArgs: []rpc.ArgDesc{
-				{"blessingHandle", ``}, // principal.BlessingsHandle
-				{"pattern", ``},        // security.BlessingPattern
+				{"handle", ``},  // principal.BlessingsHandle
+				{"pattern", ``}, // security.BlessingPattern
 			},
 			OutArgs: []rpc.ArgDesc{
 				{"", ``}, // *principal.JsBlessings
@@ -359,7 +359,7 @@
 			Name: "AddToRoots",
 			Doc:  "// AddToRoots adds the provided blessing as a root.",
 			InArgs: []rpc.ArgDesc{
-				{"blessingHandle", ``}, // principal.BlessingsHandle
+				{"handle", ``}, // principal.BlessingsHandle
 			},
 		},
 		{
diff --git a/services/wspr/internal/browspr/browspr_test.go b/services/wspr/internal/browspr/browspr_test.go
index bbb0e0a..effb936 100644
--- a/services/wspr/internal/browspr/browspr_test.go
+++ b/services/wspr/internal/browspr/browspr_test.go
@@ -17,6 +17,7 @@
 	"v.io/v23/naming"
 	"v.io/v23/options"
 	"v.io/v23/rpc"
+	"v.io/v23/security"
 	"v.io/v23/vdl"
 	vdltime "v.io/v23/vdlroot/time"
 	"v.io/v23/vom"
@@ -83,7 +84,7 @@
 	defer shutdown()
 
 	proxySpec := rpc.ListenSpec{Addrs: rpc.ListenAddrs{{"tcp", "127.0.0.1:0"}}}
-	proxyShutdown, proxyEndpoint, err := profiles.NewProxy(ctx, proxySpec)
+	proxyShutdown, proxyEndpoint, err := profiles.NewProxy(ctx, proxySpec, security.AllowEveryone())
 	if err != nil {
 		t.Fatalf("Failed to start proxy: %v", err)
 	}