{"record":{"id":"4c1102b3d11fa244","repo":"grpc/grpc-go","slug":"authinfo-is-nil","errorCode":null,"errorMessage":"AuthInfo is nil","messagePattern":"AuthInfo is nil","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"credentials/credentials.go","lineNumber":295,"sourceCode":"// in ctx.\n//\n// This API is experimental.\nfunc ClientHandshakeInfoFromContext(ctx context.Context) ClientHandshakeInfo {\n\tchi, _ := icredentials.ClientHandshakeInfoFromContext(ctx).(ClientHandshakeInfo)\n\treturn chi\n}\n\n// CheckSecurityLevel checks if a connection's security level is greater than or equal to the specified one.\n// It returns success if 1) the condition is satisfied or 2) AuthInfo struct does not implement GetCommonAuthInfo() method\n// or 3) CommonAuthInfo.SecurityLevel has an invalid zero value. For 2) and 3), it is for the purpose of backward-compatibility.\n//\n// This API is experimental.\nfunc CheckSecurityLevel(ai AuthInfo, level SecurityLevel) error {\n\ttype internalInfo interface {\n\t\tGetCommonAuthInfo() CommonAuthInfo\n\t}\n\tif ai == nil {\n\t\treturn errors.New(\"AuthInfo is nil\")\n\t}\n\tif ci, ok := ai.(internalInfo); ok {\n\t\t// CommonAuthInfo.SecurityLevel has an invalid value.\n\t\tif ci.GetCommonAuthInfo().SecurityLevel == InvalidSecurityLevel {\n\t\t\treturn nil\n\t\t}\n\t\tif ci.GetCommonAuthInfo().SecurityLevel < level {\n\t\t\treturn fmt.Errorf(\"requires SecurityLevel %v; connection has %v\", level, ci.GetCommonAuthInfo().SecurityLevel)\n\t\t}\n\t}\n\t// The condition is satisfied or AuthInfo struct does not implement GetCommonAuthInfo() method.\n\treturn nil\n}\n\n// ChannelzSecurityInfo defines the interface that security protocols should implement\n// in order to provide security info to channelz.\n//\n// This API is experimental.","sourceCodeStart":277,"sourceCodeEnd":313,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/credentials/credentials.go#L277-L313","documentation":"Returned by credentials.CheckSecurityLevel when the AuthInfo argument is nil. This function is typically called by PerRPCCredentials implementations (e.g., STS, oauth) via credentials.RequestInfoFromContext to verify the connection meets a minimum security level before attaching per-RPC credentials. A nil AuthInfo means the request context has no security information, usually because the RPC was made over an insecure channel or the credentials were invoked outside a real RPC.","triggerScenarios":"A PerRPCCredentials.GetRequestMetadata implementation calls credentials.CheckSecurityLevel(ri.AuthInfo, ...) where ri.AuthInfo is nil. This happens when the channel uses insecure.NewCredentials (no transport security), when RequestInfo was not populated (custom invocation outside gRPC), or in unit tests that call GetRequestMetadata with a bare context.","commonSituations":"Developers attach per-RPC credentials (like OAuth tokens) to an insecure channel, or test GetRequestMetadata without using credentials.NewContextWithRequestInfo. Also occurs when a custom call-credential implementation is invoked on a stream that bypassed the normal transport handshake.","solutions":["Ensure the channel uses TLS or another transport security mechanism so that AuthInfo is populated.","In unit tests, build the context with credentials.NewContextWithRequestInfo(ctx, credentials.RequestInfo{AuthInfo: ...}) to simulate a secured connection.","If the service genuinely allows insecure connections, skip CheckSecurityLevel or handle the nil-AuthInfo case explicitly before calling it."],"exampleFix":"// before\ncreds := &oauth.TokenSource{TokenSource: ts}\nconn, _ := grpc.Dial(addr, grpc.WithInsecure(), grpc.WithPerRPCCredentials(creds)) // AuthInfo is nil\n// after\nconn, _ := grpc.Dial(addr, grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)), grpc.WithPerRPCCredentials(creds))","handlingStrategy":"validation","validationCode":"// Before CheckSecurityLevel, verify AuthInfo is populated:\nri, ok := credentials.RequestInfoFromContext(ctx)\nif !ok || ri.AuthInfo == nil {\n    return status.Error(codes.Unauthenticated, \"no security info; use a secure channel\")\n}\nif err := credentials.CheckSecurityLevel(ri.AuthInfo, credentials.PrivacyAndIntegrity); err != nil {\n    return err\n}","typeGuard":"func hasAuthInfo(ctx context.Context) bool {\n    ri, ok := credentials.RequestInfoFromContext(ctx)\n    return ok && ri.AuthInfo != nil\n}","tryCatchPattern":"if err := credentials.CheckSecurityLevel(ri.AuthInfo, level); err != nil {\n    if ri.AuthInfo == nil {\n        // channel lacks transport security; upgrade to TLS\n    }\n    return err\n}","preventionTips":["Always use grpc.WithTransportCredentials(TLS) on channels that carry per-RPC credentials.","In tests, use credentials.NewContextWithRequestInfo with a populated AuthInfo.","Guard CheckSecurityLevel with a nil check on AuthInfo first."],"tags":["go","grpc","credentials","security","per-rpc"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}